Jon Galloway

ASP.NET MVC Authentication - Customizing Authentication and Authorization The Right Way

We're continuing the ASP.NET Authentication series (yes, I'm doing a few overlapping series, and yes, it's making me dizzy). The previous post covered Global Authentication and Allow Anonymous. This one continues with a simple tip that can be summed up as follows: keep it simple by extending rather than rewriting.

I see a lot of questions that involve unnecessary complications, and very often it's due to customizing authentication and authorization. For example, developers see that the AuthorizeAttribute won't work for their case, so they start to write a lot of code - using HttpModules, custom view engines, injecting authentication services and sprinkling authorization service calls throughout their controllers, etc.

Sometimes that's necessary, but it's rare. Most of the time you can handle things with either a custom membership provider, a subclassed AuthorizeAttribute, or both. Craig Stuntz summed this up well in a blog post back in 2009:

If you are developing a web application which requires authentication or security features not included in the regular ASP.NET membership feature, you might decide to implement these features yourself. But it seems as if the first instinct of many ASP.NET MVC developers is to do this by customizing their Controllers, because they’ve decided that AuthorizeAttribute can’t possibly serve their needs. They will decide that the way to do this is to write some sort of parent Controller type which examines the currently logged-in user when an action executes and changes the result of the action based on who they are. Others will try to re-implement AuthorizeAttribute without ever examining the source code for the original.

These are very bad approaches, for two important reasons:

  1. They don’t work. If your action result is cached by ASP.NET, then the action will not even run the next time it is requested. AuthorizeAttribute handles this correctly. Code you write in a Controller cannot handle this. Code you write in a custom action filter could work, if you cut and paste the implementation from AuthorizeAttribute. But AuthorizeAttribute is unsealed, so why cut and paste, when you can subtype?
  2. The modularity is wrong. You should aim to develop MVC sites which can be used with any authentication (or role) provider, whether it is ASP.NET membership, domain authentication, OpenId, or a custom membership provider. Wiring authentication concerns into a Controller makes this extremely difficult.

Craig recommends the same thing I'll be recommending - leverage the existing security systems in ASP.NET and ASP.NET MVC.

ASP.NET MVC's authorization system runs directly on top of the existing ASP.NET security system, and both have well established and tested extensibility points.

  • If you need to customize the way ASP.NET MVC integrates with the underlying ASP.NET security system, subclass the AuthorizeAttribute
  • If you need to customize the way the underlying ASP.NET membership system works, leverage the existing ASP.NET security provider system

I'll throw in one more - make sure you really need to customize anything at all.

Step Zero: Do you need to customize anything?

I've seen some examples that use the techniques below to implement authorization features... which didn't need implementing because they were already built in. AuthorizeAttribute, for example, already includes support for role-based authorization, but I've seen sample code that "adds in" role checking.

I've also seen examples which were built because the author assumed that AuthorizeAttribute only worked with Forms Authentication. That's not true - it just verifies if the user (1) is authenticated (2) is in the listed users and/or roles (if any are set). The same AuthorizeAttribute works with other authentication methods - the same attribute is also used with Windows Forms in the Intranet Application template, as well.

The AuthorizeAttribute has a pretty narrowly defined job, so it doesn't take much work to verify whether it already does what you need - check first.

Quick Note: Authentication and Authorization

Any sufficiently long article on web security must eventually devolve into distinguishing between authentication and authorization, so here goes:

  • Authentication is the act of establishing who the user is.
  • Authorization is the act of determining if that user should have access to a resource.

A user may be authenticated but not authorized to access a resource - e.g. a simple user isn't authorized to access site administration pages. A user may be authorized, but not authenticated - e.g. a site which allows anonymous access, a site which controls access using an API / access key, etc.

Customizing ASP.NET MVC's Interaction with ASP.NET Authorization by subclassing AuthorizeAttribute

Subclassing an AuthorizeAttribute is pretty straightforward. In most cases you just create a class that inherits form AuthorizeAttribute and override AuthorizeCore. Here's a very simple example: a key based login.

A simple key based AuthorizeAttribute

In this example, we'll be setting up a custom authorization scheme based on a key which will be validated using a very simple algorithm. This isn't secure for any number of reasons, but with some minor modifications (e.g. expiring a key once it is used) it would be sufficient for things like simple beta program for a pre-release website.

We'll accept a parameter called X-Key and validate that it's a number that passes a simple check.

To start with, we'll create a new class called KeyAuthorizeAttribute that inherits from AuthorizeAttribute:

public class KeyAuthorizeAttribute : AuthorizeAttribute  
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        string key = httpContext.Request["X-Key"];
        return ApiValidatorService.IsValid(key);
    }
}

public static class ApiValidatorService
{
    public static bool IsValid(string key)
    {
        int keyvalue;

        if (int.TryParse(key, out keyvalue))
        {
            return keyvalue % 2137 == 7;
        }
        return false;
    }
}

This AuthorizeCore method checks a value (via header, querystring, form post, etc.) and calls into a service to validate it. In this case, validation is a simple static method that runs our validation algorithm. In your case, you'd probably want to check against a list of pre-issued keys in a database, call out to an external service, etc. AuthorizeCore returns a boolean value - pass or fail.

We can then slap that [KeyAuthorize] attribute on any action or controller in the site, or register it globally (as shown in my previous post).

This request would be allowed: http://localhost:8515/?X-Key=26381272 (because 26381272 mod 2137 equals 7)

This request would be denied: http://localhost:8515/?X-Key=12345

Handling Authorization Failures

AuthorizeAttribute is based on Forms Authentication, so when a request fails a call to the AuthorizeCore method of an applicable AuthorizeAttribute, it will by default redirect to the login page so that, hopefully, the user can get authorized. I walked through the mechanics of this redirection process in a previous post.

The default login page doesn't make any sense in a lot of scenarios, including the example above. If someone comes to my site with a missing or incorrect API key, the login page isn't going to help them. For that specific case, I'd perhaps want to redirect them to a page that tells them how to apply for an access key.

If you need to change what happens when users fail authentication, you've got a few options:

  1. If you want to change the site-wide redirection URL for when a request fails authorization, you can change the authentication/forms/loginUrl setting in web.config. Keep in mind, though, that this affects all authentication redirects for your entire application.
  2. If you want to run custom logic - including but not limited to redirecting to a URL - you can override the AuthorizeAttribute's HandleUnauthorizedRequest method.

Many more examples

This is a very simple example. You can find a lot more by searching on the override code above, e.g. "override authorizecore httpcontextbase". Some examples:

Note: The last one on the list implements the base AuthorizeAttribute interfaces rather than subclassing AuthorizeAttribute, which bears some discussion.

Subclass AuthorizeAttribute or Implement FilterAttribute, IAuthorizationFilter?

If you just look at the AuthorizeCore code in the AuthorizeAttribute, you may think it's so trivial you might as well just build your own IAuthorizationFilter from scratch. The problem with that idea is that it's very easy to do that incorrectly. A large amount of the code in the AuthorizeAttribute is there to make sure it works correctly with caching. If you get this wrong, you can very easily open yourself up to this scenario:

  1. Authorized user accesses an action and is correctly granted access.
  2. The action uses output caching, so the output is cached for future views.
  3. Unauthorized user accesses the action. Since it was cached, the restricted (or user-specific) content is served to the unauthorized user.

The AuthorizeAttribute has ensured that the code in the CacheValidateHandler and OnCacheAuthorization methods interact correctly with ASP.NET's caching system. Unless you really know what you're doing, it's a much better idea to start by subclassing AuthorizeAttribute.

Using AuthorizeAttribute with ASP.NET Web API

ASP.NET Web API uses the same AuthorizeAttribute scheme. It works the same way - drop an attribute on actions, API controllers, or globally, and you're set. All good so far.

But, if you use System.Web.Mvc.AuthorizeAttribute (or a subclassed attribute) on an Action Controller, nothing will happen. ASP.NET Web API uses a very similar, but different AuthorizeAttribute, found in the System.Web.Http namespace. There are some important differences (beyond the scope of this post), but a good place to look is at how the two AuthorizeAttributes handle unauthorized requests:

This reflects the difference between the target focus of both systems - ASP.NET MVC primarily focuses on HTML code that's viewed by people in a browser, and ASP.NET Web API primarily focuses on HTTP traffic that's handled by code. In ASP.NET Web API, you don't tell someone they're not authorized with a login page, you return the appropriate HTTP status code.

Fluent Security

If you have complex authorization requirements - particularly around configuration - you might want to look at Fluent Security. It provides a fluent, code-based configuration system, which lets you do define your application's authentication requirements in one place, like this:

SecurityConfigurator.Configure(configuration =>
{
    // Let Fluent Security know how to get the authentication status of the current user
    configuration.GetAuthenticationStatusFrom(() => HttpContext.Current.User.Identity.IsAuthenticated);

    // Let Fluent Security know how to get the roles for the current user
    configuration.GetRolesFrom(() => MySecurityHelper.GetCurrentUserRoles());

    // This is where you set up the policies you want Fluent Security to enforce
    configuration.For<HomeController>().Ignore();

    configuration.For<AccountController>().DenyAuthenticatedAccess();
    configuration.For<AccountController>(x => x.ChangePassword()).DenyAnonymousAccess();
    configuration.For<AccountController>(x => x.LogOff()).DenyAnonymousAccess();

    configuration.For<BlogController>(x => x.Index()).Ignore();
    configuration.For<BlogController>(x => x.AddPost()).RequireRole(BlogRole.Writer);
    configuration.For<BlogController>(x => x.AddComment()).DenyAnonymousAccess();
    configuration.For<BlogController>(x => x.DeleteComments()).RequireRole(BlogRole.Writer);
    configuration.For<BlogController>(x => x.PublishPosts()).RequireRole(BlogRole.Owner);
});

GlobalFilters.Filters.Add(new HandleSecurityAttribute(), 0);

Customizing ASP.NET MVC Authorization using the existing ASP.NET Security systems

ASP.NET has been around for a long time. It's been beaten on pretty hard, and the existing systems have undergone a huge amount of real-world testing. When you run into a constraint that pushes you towards writing some custom code, the best approach is to make sure you understand how the existing systems work and integrate with them as closely as possible.

Since ASP.NET has been around for a long time, there is a good amount of existing information on the security system. It's a big topic. I'm just going to (try to) summarize, pointing out the best extension points from an ASP.NET MVC point of view.

Extending the Forms Authentication provider

As mentioned earlier, authentication is the process of establishing who the user is. It doesn't say anything about what access you've got, it just verifies that you are who you claim to be. ASP.NET has some built in systems to handle that - the Forms Authentication provider handles browser based login and account management, and there's a Windows Authentication provider which integrates with the Windows authentication. If you need to modify how authentication works, you'll almost certainly be working with the Forms Authentication provider.

You might assume that you extend authentication by plugging in a new Authentication Provider, but that's not the case. There are two in the box Authentication Providers, and you can't add new ones. That's pretty much never an issue, though, because the Forms Authentication provider gives you plenty of hooks for extension.

Warning: The next paragraph is exceptionally nerdy, but it sets some important background for interfacing with Forms Authentication.

Forms Authentication uses a Forms Authentication Ticket to track your identity - essentially your authenticated username. The ticket is stored in an encrypted Forms Authentication Cookie.  There's support for cookieless authentication, which automatically appends cookie information via an encrypted querystring value. There are two main components that make Forms Authentication work - the FormsAuthetication class which sets the authentication cookie for authenticated users, and a FormsAuthenticationModule which checks for the cookie, authenticates you and sets your identity in the HttpContext. Since FormsAuthenticationModule is an HTTP module, it runs for every request, way at the beginning of the pipeline. That's an important part - a secure authentication system needs to check authentication at the beginning of the request.

This is all underlying machinery - the important part is that when someone logs in, something in your application calls FormsAuthentication.SetAuthCookie(). That sets the Authentication Cookie, which is then checked by the FormsAuthenticationModule on each request. You can see an example of how the default ASP.NET MVC AccountController Login method uses it:

[AllowAnonymous]
[HttpPost]
public ActionResult Login(LoginModel model, string returnUrl)
{
    if (ModelState.IsValid)
    {
        if (Membership.ValidateUser(model.UserName, model.Password))
        {
            FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
            if (Url.IsLocalUrl(returnUrl))
            {
                return Redirect(returnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "The user name or password provided is incorrect.");
        }
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

A good example is DotNetOpenAuth, which adds OpenID, OAuth, and InfoCard authentication to ASP.NET by integrating with the ASP.NET Forms Authentication ticket. You can see how this works in the DotNetOpenAuth OpenAuthAuthenticationTicketHelper.cs class, and in the OpenIdRelyingPartyMvc sample's UserController.

The important points here:

  • While it's tempting to look at your custom authentication needs as completely unique, most can be handled by determining who a user is (your code) and then telling ASP.NET Forms Authentication to track them.
  • If you decide that you'd rather just handle authentication outside of ASP.NET, you've got a lot to think about. You'll be writing a lot of new code which hasn't gone through near the security testing, beating, improvements, etc., that Forms Authentication has.

The ASP.NET Roles and Membership System

The above authentication discussion was completely independent of where and how the actual user information was stored, and that's important. Forms Authentication doesn't handle passwords, logins, user roles, etc., it just tracks users once it's been told about them.

ASP.NET Membership

The default system for managing user and is ASP.NET Membership. There's a SqlMembershipProvider that runs against a SQL Server database, but the provider system allows you to plug in your own custom Membership Provider for managing users. Your login process can use your membership provider to validate the user's credentials, and you can use the membership system to store user information if you want. More on that in a bit.

ASP.NET Role Management

For some sites, authorization and authentication are nearly synonymous - the only goal of authorization is to prevent anonymous access. But for many sites, you've got different roles - users, administrators, superadministrators, and omegasupremeadministrators. For those cases, you need something that maps users to roles, and that's what Role Management Providers do. In most cases, roles and membership are managed together - the same system that tracks who your users are controls what rights they have. You'll often see role and membership providers in one big package, but they're two separate things.

Customizing Membership in ASP.NET

As before, the zeroth rule of customizing membership is to reconsider if you need to. There are plenty of hooks into the existing flow, such as overriding OnAuthorization and just adding some information to HttpContext.Items, Session, etc.

If you really do need a custom user management system, the first thing to do is look to see if someone's already written it. There are membership providers for a lot of backing systems. A quick search shows tons of them:

Implementing your own Membership Provider

If you don't find a Membership Provider that works for you, it's not difficult to write your own. Remember that you're taking more responsibility for your system's security. Matt Wrock wrote a great overview: Implementing custom Membership Provider and Role Provider for Authenticating ASP.NET MVC Applications.

There's plenty of information on MSDN as well, for example: Implementing a Membership Provider

Simple Membership

You'll notice that a lot of Matt's overview of creating Membership and Role Providers included a lot of System.NotImplementedException, because the ASP.NET Membership Provider system shows some underlying assumptions around user data going in relational databases. You can just ignore those parts and use what you want, but if you find the whole thing a little too complex and are tempted to throw it all out, I'd recommend looking at SimpleMembership from ASP.NET Web Pages.

Matthew Osborn wrote an overview of what SimpleMembership is and how it works in ASP.NET Web Pages. Although it was originally written for ASP.NET Web Pages, it can be readily adapted to ASP.NET MVC using the SimpleMembership.Mvc NuGet package.

Wrapping Up

ASP.NET MVC gives you a huge amount of flexibility, and it's tempting to want to write a lot of custom code. If you understand the underlying security systems that ASP.NET MVC uses, though, you can usually integrate with what's in place. You'll be saving yourself a lot of unnecessary code, along with the added costs of testing, debugging and maintenance. More important, though, you'll be using a system that's undergone a huge amount of security testing over the past decade.

For further study:

Posted by Jon Galloway | 30 comment(s)
Filed under: ,

Upcoming Web Camps

We've got some great, free Web Camps headed your way!

Web Camps are free, fun, no-fluff events for developers, by developers. Show up for the day, leave infused with a crazy amount of web dev info. Did I mention these are free?

My teammate Brady Gaster has put together some phenomenal new content, and I'm really looking forward to presenting at some of these.

Web Camps Locations

So far the following locations have been announced:

Location Date Registration Notes
Brussels, Belgium 3-May-12 Register Here With Brady Gaster and Matthew Osborn... and there's still room!
Waltham, MA 10-May-12 Register Here I'll be here! Also starring Chris Bowen and Jim O'Neil!
Mountain View, CA 14-May-12 Register Here With the amazing Doris Chen!
Denver, CO 18-May-12 Register Here Also Doris Chen!
Phoenix, AZ 25-May-12 Register Here Also Doris Chen! Wow, she's busy!
Mountain View, CA 29-May-12 Register Here I'll be here! Maybe someone else, too.

There are a bunch more that are in the works but not quite ready to be announced yet - I'll update here, but the best place to keep up to date is at http://www.devcamps.ms/web

Oh, and I believe there's still room at the Web Camp in Brussels on May 3.

Web Camps Content

I've reviewed and contributed a bit to the Web Camps content that Brady's put together, and it's really, really good. There's a ton of information packed in. Here's an overview of the agenda (see the registration link for the exact agenda at each location):

  • Welcome Back to the Microsoft Web Stack
  • Integrating Your Site with Internet Explorer 9
  • Top 10 Things You Didn't Know about WebMatrix 2
  • Creating Rich HTML 5 Experiences
  • Building Web Sites Using ASP.NET 4.5
  • Building a Service Layer with ASP.NET Web API
  • Deploying ASP.NET Apps to the Cloud

You can read more about those topic at http://www.devcamps.ms/web/agenda.

Infomercial!

Now if you're almost convinced, but on the edge, and you need a video to push you over the top, you watch Brady and me announcing the Web Camps tour on Web Camps TV a few weeks ago:

Yes, if you read my blog you'll have noticed that this video is a repeat. That's how infomercials work.

Posted by Jon Galloway | 1 comment(s)
Filed under:

Windows 8 and ASP.NET Web API - Part 1 - Getting Started

Many of the key Windows 8 Metro Style application features either require or can greatly benefit from a connection to online services. ASP.NET Web API is a great fit for these services, as it's tightly focused around providing HTTP services to applications. I'm starting a series that will look at how to leverage ASP.NET Web API services from Windows 8 applications.

In this first post in the series, we'll begin with a simple C# Windows 8 Metro Style application that displays data from the ASP.NET Web API Contact Manager sample. Once we've got the basics locked down, we'll move on to some more complex topics. I'm thinking Live Tiles and Notifications, but I'm interested in your ideas of where to go next, so please let me know in the comments.

The ASP.NET Web API Contact Manager sample

I thought it would be simplest to start with an official, tried and true Web API sample that's been around since the early days of WCF Web API - the Contact Manager Sample. You can download the code here: http://code.msdn.microsoft.com/Contact-Manager-Web-API-0e8e373d

This code is originally written for Visual Studio 2010, but I'm going to be working on Visual Studio 11 Beta running on Windows 8 Consumer Preview, so I ran through the upgrade. There's an alert which says "One or more Web Application projects in this solution require SQL Server Express. You will need to download and install the appropriate version of SQL Server Express for these projects to work." A quick look at the code, however shows that all the data is in-memory, so we can ignore it. If we keep with this code for long, we can just remove the offending NuGet package, but let's not let that slow us down just yet.

Running the application shows that the application is indeed working.

2012-04-27_01h26_16

The HTML client page is making an .getJSON() call back to the Web API service, which returns a list of contacts in JSON format, then uses jQuery templating to display the contacts in HTML format. That jQuery templating should probably be updated to use the newer JSRender system, but it doesn't really matter for this example, since we're just concerned about the services, not the HTML client.

Looking at the ASP.NET Web API's services using F12 developer tools

We're going to be using Fiddler2 in a bit, but since the simplest way to view the output of the Web API's JSON services is in a browser. In IE, you do that by pressing the F12 hotkey to display developer tools - it looks like this:

2012-04-27_02h01_20

Now switch to the Network view (or your browser's equivalent), start monitoring, and browse to /contacts (in my case the full URL is http://localhost:33936/contacts, your port number will vary). IE prompts you to download the JSON file and the browser's address bar goes back to the previous. That's a little wacky - other browsers display the JSON as text - but the service call response is included in the results. Clicking on it to bring up the detailed view and showing the response body shows the JSON data:

2012-04-27_02h09_00

The JSON data returned is as follows (I removed some of the contacts from the list for brevity):

[ { "Address" : "1 Microsoft Way",
    "City" : "Redmond",
    "ContactId" : 1,
    "Email" : "example@microsoft.com",
    "Name" : "Glenn Block",
    "Self" : "contact/1",
    "State" : "Washington",
    "Twitter" : "gblock",
    "Zip" : "98112"
  },
  { "Address" : "1 Microsoft Way",
    "City" : "Redmond",
    "ContactId" : 2,
    "Email" : "example@microsoft.com",
    "Name" : "Howard Dierking",
    "Self" : "contact/2",
    "State" : "Washington",
    "Twitter" : "howard_dierking",
    "Zip" : "98112"
  },
  { "Address" : "1 Microsoft Way",
    "City" : "Redmond",
    "ContactId" : 3,
    "Email" : "example@microsoft.com",
    "Name" : "Yavor Georgiev",
    "Self" : "contact/3",
    "State" : "Washington",
    "Twitter" : "digthepony",
    "Zip" : "98112"
  }]

That content's being returned from the ContactsController's Get action, which just returns a Queryable list:

public IQueryable Get()
{
    return this.repository.GetAll().AsQueryable();
}

Out of the box, ASP.NET Web API can format data in JSON and XML format, so the output is automatic depending on content negotiation. If you're familiar with ASP.NET Web API, this is all pretty standard stuff. If you're not, I recommend the ASP.NET Web API content section at http://asp.net/web-api and my previous blog / screencast series on getting started with ASP.NET Web API.

The point is that this sample is producing JSON data that we can display in our Windows 8 Metro application.

Creating a Windows 8 Metro style application using the Blank template

To create the Windows 8 Metro application, add a new project using the File / Add / New Project... dialog. Select the Visual C# / Windows Metro Style section, then pick the Blank Application template. I called mine ContactManagerMetro because I have no imagination.

2012-04-27_00h49_24

Why the Blank Application template? Good question. I started with the Split Application template, but it has existing data structures which are hierarchical (since the Split Application helps with navigating structured content), so it wasn't a good fit. I think the Blank Application template is a good start since it's nice and simple.

This application is, as promised, rather blank. The main form is even called BlankPage.xaml, which while being rather descriptive of the initial state, seems unlikely to remain accurate for very long in most cases. Since we're just proving concepts at this point, though, I'm going to grit my teeth and leave the name as BlankPage.xaml. Focus.

Writing the Metro Application XAML

We've got a lot of options for how to display the contact information, but I think a good start is using the same kind of display that the original HTML view used. In the Metro XAML land, that's usually done using a ListView. Inside BlankPage.xaml's empty grid, I'm going to add the following ListView markup:

<GridView x:Name="ContactList">
    <GridView.ItemTemplate>
        <DataTemplate>
            <StackPanel Width="200" Height="150" Margin="10" Background="#FF161C8F">
                <TextBlock Text="{Binding Name}" FontSize="24" />
                <TextBlock Text="{Binding Address}" />
                <TextBlock Text="{Binding City}" />
                <TextBlock Text="{Binding State}" />
                <TextBlock Text="{Binding Zip}" />
                <TextBlock Text="{Binding Twitter}" />
            </StackPanel>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

This is pretty rudimentary, we'll clean it up later. The main reason I'm writing it now is to make sure I know what I'll be binding to, and for the above TextBlock binding values I just based the values off the contact properties returned by the service.

Calling the Web API service from our Metro Application

Calling the service is actually pretty straightforward. First, I'll use the System.Net.Http.HttpClient to call the service. As all external calls in WinRT are async, I need to handle that. Fortunately the async/await keywords make that really easy.

Since our service returns JSON, I'm going to leverage the utility classes in the Windows.Data.Json namespace to parse it. The code is a little repetitive and could definitely use some refactoring, but it handles the job of mapping JSON values to an anonymous object. Tim Heuer recently blogged about using that with anonymous type binding, and I liked his approach.

With all the plumbing in place, I'll call this GetContacts() method from my OnNavigatedTo event.

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    GetContacts();
}

public async void GetContacts()
{
    var serviceuri = "http://localhost:33936/contacts";
    var client = new System.Net.Http.HttpClient();

    var response = await client.GetAsync(serviceuri);
    if (response.IsSuccessStatusCode)
    {
        var data = await response.Content.ReadAsStringAsync();
        var contacts = JsonArray.Parse(data);

        var qry = from m in contacts
            select new
            {
                Name = m.GetObject()["Name"].GetString(),
                Address = m.GetObject()["Address"].GetString(),
                City = m.GetObject()["City"].GetString(),
                State = m.GetObject()["State"].GetString(),
                Zip = m.GetObject()["Zip"].GetString(),
                Twitter = m.GetObject()["Twitter"].GetString(),
            };

        ContactList.ItemsSource = qry;
    }
}

This calls into our service and displays the following data:

Screenshot

Hurrah! We got data from our service and viewed it in the app. It's pretty ugly, though. Let's clean up the formatting a bit so it matches the original app a little better. I'm using the underappreciated <Run> XAML element for that:

<GridView x:Name="ContactList">
    <GridView.ItemTemplate>
        <DataTemplate>
            <StackPanel Width="250" Height="150" Margin="10" Background="#FF161C8F">
                <TextBlock Text="{Binding Name}" FontSize="28" Margin="10,20,10,0" />
                <TextBlock Margin="10,0">
                    <Run Text="{Binding Address}" />, <Run Text="{Binding City}" />
                </TextBlock>
                <TextBlock Margin="10,0">
                    <Run Text="{Binding State}" /> <Run Text="{Binding Zip}" />
                </TextBlock>
                <TextBlock Margin="10,0">
                    @<Run Text="{Binding Twitter}" />
                </TextBlock>
            </StackPanel>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

That at least organizes the text a bit:

Screenshot (2)

And that's at least a decent start. Questions? Where should we go next?

ASP.NET MVC Authentication - Global Authentication and Allow Anonymous

As I was recently updating the Wrox Professional ASP.NET book for ASP.NET MVC 4, I thought about some of the common questions, tip, and tricks I've seen over the past few years, and thought it was time for a... quick blog series! Let's start with Global Authentication.

ASP.NET MVC has had an Account Controller since the ASP.NET MVC 1.0 preview releases; it handles login and registration. That, by itself, just allows users to get logged in - it doesn't do anything to restrict access. That's where the AuthorizeAttribute comes into play. AuthorizeAttribute is a Filter attribute which can be placed on ASP.NET MVC actions or entire controllers to prevent unauthorized access. Attempting to access a restricted controller action when you're not authorized redirects you to login, as I previously described in quite gory detail in a previous post titled Looking at how the ASP.NET MVC Authorize interacts with ASP.NET Forms Authorization.

Reminder: Don't use web.config to restrict access, use [Authorize]

Note: This is old news to MVC veterans, but bears repeating because it continues to be a common question and is really important to get right.

In ASP.NET Web Forms, requests mapped to physical files. There's an <authorization> element  in web.config which can be used to restrict file-based access. So this worked well for ASP.NET Web Forms and file-based authorization in general.

But it's a very bad idea to use web.config based authorization in ASP.NET MVC, because URL's map to actions via routing, which can change. You may have multiple routes that map to the same controller action, or you may change routes over time. AuthorizeAttribute was built specifically for this purpose, because you can place your security directly on the resource (the action or controller). Change the routes all you want, the authorization rules go along with the actions.

Another interesting note here is that, since ASP.NET Web Forms has supported routing since ASP.NET 4, you need to pay closer attention to securing routes there as well. K. Scott Allen discussed that in an MSDN Magazine article a few years ago, Routing with ASP.NET Web Forms.

The progression of global authentication in ASP.NET MVC

The AuthorizeAttribute works pretty well, but you have to put it on every controller (or action, if you need to be that granular) that needs to be secured. That's tedious and error prone, and if you forget it, you've opened your site up to anonymous access. In many cases, it's preferable to restrict access to the entire site except for the the Login and Register actions. That's become a little easier with each release, to the point where in ASP.NET MVC 4 I think it's finally about right.

Rick Anderson wrote two comprehensive posts on this - and authorization in ASP.NET MVC in general - in a pair of posts covering security in ASP.NET MVC:

ASP.NET MVC 1 and 2 - Custom Controller Base

In the first post, Rick explains that prior to ASP.NET MVC 3, the recommended approach was to create a custom Controller base class with an [Authorize] attribute applied. This probably sounds more complicated than it is, because it's really easy:

  1. Right-click the Controllers folder and add a new Controller. Call it something like AuthorizedController.
  2. Delete the Index action.
  3. Add the [Authorize] attribute to the class.
  4. Clean up the Using block at the top if you care about that kind of thing.

End result:

using System.Web.Mvc;

namespace InstantMonkeysOnline.Controllers
{
    [Authorize]
    public class AuthorizedController : Controller
    {
    }
}

Now you can use this AuthorizedController base class for any other controllers in your application. Changing the HomeController base class to inherit from AuthorizedController will require authorization to view the site home:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace InstantMonkeysOnline.Controllers
{
    public class HomeController : AuthorizedController
    {
        public ActionResult Index()
        {
            ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";

            return View();
        }

        //More actions here
    }
}

The downside is that you have to remember to do this, so unless you change the T4 templates, you're setting yourself up for an easy mistake down the road.

ASP.NET MVC 3 - Global Action Filters

ASP.NET MVC 3 made it easy to apply an action filter to all actions in your application. If you look in the Global.asax in an new ASP.NET MVC 3 (or later) application, you'll see a RegisterGlobalFilters method.

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
}

To require authorization throughout your application, you could just register AuthorizationAttribute, right?

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new HandleErrorAttribute());
    filters.Add(new AuthorizeAttribute());
}

Unfortunately, this works a little too well - it's global, so users can't login. But, really, really secure, right?

Rick proposed a custom LoginAuthorizeAttribute which inherited from AuthorizeAttribute but added an exception for the AccountController, but Levi Broderick (an ASP.NET team member who's a whiz with web security) recommended using a filter to whitelist actions which should be available for anonymous access.

using System.Web.Mvc;
using MvcGlobalAuthorize.Controllers;

namespace MvcGlobalAuthorize.Filters {
    public sealed class LogonAuthorize : AuthorizeAttribute {
        public override void OnAuthorization(AuthorizationContext filterContext) {
            bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true)
            || filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true);
            if (!skipAuthorization) {
                base.OnAuthorization(filterContext);
            }
        }
    }
}

So now you'd register LogonAuthorize as a global filter, and to allow access to an action, you'll need that AllowAnonymousAttribute. Since it's just a marker attribute, there's no actual code - just attribute usage settings.

using System;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, 
                AllowMultiple = false, Inherited = true)]
public sealed class AllowAnonymousAttribute : Attribute { }

ASP.NET MVC 4 and the AllowAnonymous attribute

The good news is that this is even easier in ASP.NET MVC 4, because it's baked in. By baked in, I mean that:

  • There's a built-in AllowAnonymousAttribute in the the System.Web.Mvc namespace which whitelists actions for anonymous access
  • The AuthorizeAttribute filter has built-in logic that allows access to actions decorated with the AllowAnonymousAttribute

That means that you can just register the AuthorizeAttribute as a global filter and put the AllowAnonymousAttribute on any actions that should be public.

If you use the AllowAnonymousAttribute without registering AuthorizeAttribute there's no effect. For that reason, the default AccountController in a new ASP.NET MVC 4 project has [AllowAnonymous] on all the actions that should always be public:

[Authorize]
public class AccountController : Controller
{
    [AllowAnonymous]
    public ActionResult Login()

    [AllowAnonymous]
    [HttpPost]
    public JsonResult JsonLogin(LoginModel model, string returnUrl)

    [AllowAnonymous]
    [HttpPost]
    public ActionResult Login(LoginModel model, string returnUrl)

    public ActionResult LogOff()

    [AllowAnonymous]
    public ActionResult Register()

    [AllowAnonymous]
    [HttpPost]
    public ActionResult JsonRegister(RegisterModel model)

    [AllowAnonymous]
    [HttpPost]
    public ActionResult Register(RegisterModel model)

    public ActionResult ChangePassword()

    [HttpPost]
    public ActionResult ChangePassword(ChangePasswordModel model)

    public ActionResult ChangePasswordSuccess()
}

That works because, as mentioned above, the AuthorizeAttribute has the following logic (as you can see from the code on CodePlex):

bool skipAuthorization = filterContext.ActionDescriptor.IsDefined(
		typeof(AllowAnonymousAttribute), inherit: true)
	|| filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(
		typeof(AllowAnonymousAttribute), inherit: true);

if (skipAuthorization)
{
    return;
}

Note: I actually started looking into this in detail because I was wondering how the AllowAnonymousAttribute was able to bypass the Authorization check, and was surprised to see that it didn't have any code at all. I wasn't alone here, I noticed David Hayden looked into this as well.

If you're interested in more information on ASP.NET MVC security and the history of the AnonymousAttribute, I highly recommend Rick's posts listed above. He goes into a lot more detail - with some excellent input from Levi - on what not to do (e.g. put security logic into routing) and further considerations like requiring HTTPS globally.

Posted by Jon Galloway | 17 comment(s)
Filed under:

I've joined the Windows Azure technical evangelist team

I've been at Microsoft for a little over two years now, working in groups that focused primarily on publishing online content for developers. In addition to the obvious things, there's a lot of work that goes on behind the scenes in creating and maintaining content  - maintaining and improving existing content, planning content for unreleased platforms and products, handling dozens of spoken languages and several programming languages, etc. It's been a pleasure working with some real professionals. I've also enjoyed working in a small but dynamic group that's focused on the developer community. During that time I had two excellent bosses, Scott Hanselman and Pete Brown. Both really made it fun to show up to work every day. Well, I work from home, but still.

I'm excited about my new position in the Windows Azure technical evangelist team.

Wait, what? Azure?

Yep, Azure. Let me explain why.

Azure Application Platform Team includes ASP.NET, IIS, etc.

First, you'll recall that Scott Guthrie heads the Azure Application Platform team, and that group includes ASP.NET and IIS. In the year since that transition, I've been really happy with where I've seen Microsoft's web platform going. The ASP.NET team has been cranking out some great stuff for the ASP.NET 4.5 / ASP.NET MVC 4 / ASP.NET Web Pages 2 wave (easier to just call it ASP.NET vNext). Oh, and they just open sourced a whole lot of code. So if anyone was concerned that ASP.NET would stall out in this new organization, I think this past year would allay that fear.

Azure as a good influence on Microsoft

And in fact, it seems like the influence of running Azure as a hosting platform has opened Microsoft's web development horizons a good amount. We've got people like Glenn Block working with Node.js, Microsoft shipping code on GitHub (all the Azure sdk's are on GitHub), Hadoop support on both Azure and Windows Server, etc. So if anything, Azure is really broadening Microsoft's perspective on web development. I hadn't expected that at all.

Azure future

Well. All I can say here is that I'm extremely excited about where Azure is going as a platform. As Scott Guthrie said in MSDN Flash recently, "You will see even more significant updates and features in Windows Azure in the months ahead." There are a lot of things coming together here that are making Azure very interesting for me as a developer, and I want to be in on it. Stay tuned.

Windows Azure Technical Evangelist team

This is an cool team. I'm helping (new Microsoft employee) Brady Gaster with this summer's Web Camps, learning some interesting Windows 8 dev from Nick Harris, got to meet up with Nathan Totten (I'd used his Facebook SDK in the past), and I'm just getting started. Oh, and Cory Fowler just joined up too, focusing on the open source community on Azure including PHP and Node.js. And lots of other smart folks, all focusing on different applications of Azure and the Azure application platform. James Conard has put a really good team together, and it's really energizing to be a part of it.

Nick and Nate just took over the Cloud Cover show on Channel 9 and interviewed me, along with the other three new team members: Cloud Cover - Episode 76 - Meet our new additions to the Windows Azure Technical Evangelist Team (I'm on around 14:40).

What's new for Jon

I'll be continuing to focus on ASP.NET as a platform. I like ASP.NET, and I like helping other people who are using it. Azure is a good place to put ASP.NET apps, so more ASP.NET apps helps Azure. So that means I'll continue to do thing's I've been doing in the past - blogging, speaking, writing, tutorials, screencasts about ASP.NET. But with more options for scale, travel budget, opportunities for collaboration with other groups, etc.

For example, I'll be speaking at a Web Camp in Boston on May 10 as part of the Web Camps tour that Brady's putting together. Brady invited me on Web Camps TV to help introduce Web Camps 2012:

Jon Galloway Helps Introduce Web Camps 2012

I've been doing some behind the scenes work on the ASP.NET site to make content easier to find and consume (e.g. HTML5 video support, input on responsive design). I also help with content for ASP.NET releases, like edits and publishing the ASP.NET MVC release notes, setting up things like the ASP.NET Web API content area, etc. That won't change.

So my focus stays on ASP.NET as a platform - whether you host it on Azure, IIS, or wherever else you crazy kids decide to put it.

But, as I said, I joined the Azure evangelist team because I'm excited abou it, so of course I'll be using it and talking about it as I do. For intstance, I'm thinking there are a lot of opportunities to spin up sample apps and services in Azure to show what I'm talking about.

Thoughts on ASP.NET MVC, ASP.NET Web API, and ASP.NET Web Pages (Razor) open source announcements

I'm really excited by the big announcements earlier this week:

  • The source for ASP.NET Web API and ASP.NET Web Pages (Razor) were released under Apache v2 license
  • ASP.NET Web API, ASP.NET Web Pages, and ASP.NET MVC (which was already released under MsPL license) will accept community contributions

I'm a big fan of both ASP.NET and open source, so it's exciting to see two of my favorite techy things hanging out at the same party. By now, you've likely read a few post with the actual details, very likely by one or more person named Scott, which contains some actual facts and some of the history. So here are a few recommended posts, followed by some additional commentary.

Must Read Posts

Scott Guthrie: ASP.NET MVC, Web API, Razor and Open Source

Scott Guthrie's announcement explains what's been released and how to get involved.

Scott Hansleman: ASP.NET MVC 4, ASP.NET Web API and ASP.NET Web Pages v2 (Razor) now all open source with contributions

Scott Hanselman's post is worth reading just for the animated GIF's, but he also describes some of the history and answers some common / likely questions, like

  • Why are you doing this?
  • Are you going to open source more things in ASP.NET?
  • Why isn’t ASP.NET Web Forms open sourced?
  • What about Mono?
  • Why not on GitHub?

Phil Haack: ASP.NET MVC Now Accepting Pull Requests

Phil gives some good background on what was involved in making it possible for these products to accept external contribution. More on that later.

Jimmy Bogard: ASP.NET MVC, Web API, Razor and Open Source and what it means

I really like Jimmy's post. He starts off by clarifying that open source has never required accepting external contributions, then asks and answers some good questions:

  • Will the quality of the product be adversely affected because the team accepts contributions?
  • Will some yahoo be able to sidestep my current feedback channel and take the product in some other (wrong) direction?
  • Will my pull request get accepted?
  • Will someone else’s changes be supported?
  • Are we in store for human sacrifice, dogs and cats living together, mass hysteria?
  • Can we trust these products now?
  • Is this a Good Thing?
  • Why CodePlex and not GitHub?

I'm going to assume you're familiar with the above for the rest of this post. So here's what I think about this - and as a reminder, these are my own opinions, not Microsoft position or policy or whatever.

Source visibility - What's really changed

.NET framework has never been obfuscated. We all take that for granted, but it's been really useful to me throughout my .NET development career. Come to think of it, the Visual Basic 6 (and previous versions) source code wasn't available to me - and even if it had been, it wasn't written in Visual Basic so I wouldn't have been able to read it. So there are two nice things there:

  • The fact that .NET and the frameworks built on top of it have always been available to decompile
  • Just about all of .NET and frameworks, such as ASP.NET assemblies, are written in .NET so that they can be decompiled into something .NET developers can readily understand

Several times I week, I pop open ILSpy to either figure out or verify something about how ASP.NET works, often to answer a question that'd be really difficult otherwise. It's not that there isn't plenty of documentation available - there is - but often the best way to learn how code works is to look at the code.

2012-03-29 22h29_25

While these are best disassemblers out there have been third party (e.g. Reflector, ILSpy, ), Microsoft's provided ildasm.exe from back in the .NET 1.1 days (maybe earlier?).

We've had symbols available, too, so we could debug directly into .NET source code as needed. You can point Visual Studio at Microsoft's public symbol servers and debug right into .NET source code in a couple of minutes.

2012-03-30 00h02_14

And that doesn't even get into what IntelliTrace does if you've got a Visual Studio Ultimate license.

So, the point is that we've always been able to see the source code for pretty much anything most developers would care about. ASP.NET MVC moved things along by actually releasing the ASP.NET MVC code under an open source license, but other than maybe the Mono project, I'm not aware of anyone really taking heavy advantage of it. I'd personally be really happy to hear that I'm wrong here, but just haven't heard of people doing things like building custom versions of ASP.NET MVC.

So what's the point, then?

For me, as a consumer, code that's released under an open license gives me options and peace of mind. It lets me know that, regardless of what happens to the project, the source is available for me and other users to carry it forward. Several of my favorite open source applications are forks, and that's something I consider when I invest my time in learning a new framework or application.

So, back to the earlier question... if we've always been able to view the code, what's really changed?

Two big things:

  1. Much more visibility into the development process
  2. Acceptance of community contributions

Instant Visibility

You might think that, as a Microsoft employee, I have free run of the Microsoft source code. Or at least the .NET framework code. Certainly the ASP.NET code repository, right? No, I don't. I subscribe to the source control check-in e-mails, but I've historically kept up with what was going on by talking with the team and keeping up with announcements on the ASP.NET Insiders list.

But over time, that's become less of a thing. As Scott Koon said after the last MVP Summit, he hadn't really heard a single big surprise on what the ASP.NET team was working on... and that's a very good thing. The team's been very open as to what they're up to, what they're thinking about doing in the future, etc.

And this new open source change takes things to a new level there, because they're working in a public repository. So rather than waiting on big releases - or even pre-releases - anyone can watch the checkins as they happen. That's a big deal.

Accepting community contributions

Phil Haack's written some interesting posts recently on open source. His post listed earlier highlighted the difference between code that's released under an open source license and an open source project. As Jimmy Bogard points out, there's nothing about any accepted open source definition that requires accepting community contributions. Nobody would dispute that there are huge potential benefits to code and product quality if you can accept community contributions, but a decision that needs to be made by those who run the project.

But many of the ASP.NET devs run or participate in open source proects, so why wouldn't they just open things up?

Oh, it's stupid company politics and blasted lawyers. Well, that's the simplistic thinking, anyhow. Okay, fine, the devs would like things to be open, but pointy headed bosses ruin it. Oh, and it takes a long time to change minds and steer big ships or something. It's not that simple, though.

[Disclaimer: Personal opinions following. My whole blog is generally my personal opinions unless I say otherwise, but I want to make that really clear.]

Stepping back a bit - and speaking completely for myself, and not Microsoft or any future or previous employers here - businesses that sell some kind of intellectual property (as in they paid someone's salary to create something like digital media and software) need to be careful in giving things away, in ways you wouldn't expect. I have several relatives and close friends who make or have made their livings as musicians, and have explained that it's possible to do something wrong and suddenly your hit becomes public domain and your kids don't go to college. It's the same kind of thing with software - companies that want to give things away need to navigate a complex (bizarre?) legal system that handles intellectual property in non-intuitive ways.

Phil Haack's blog post (ASP.NET MVC Now Accepting Pull Requests) spells this out well:

I also want to take a moment and credit the lawyers, who are often vilified, for their work in making this happen.

One of my favorite bits of wisdom Scott Guthrie taught me is that the lawyers’ job is to protect the company and reduce risk. If lawyers had their way, we wouldn’t do anything because that’s the safest choice.

But it turns out that the biggest threat to a company’s long term well-being is doing nothing. Or being paralyzed by fear. And fortunately, there are some lawyers at Microsoft who get that. And rather than looking for reasons to say NO, they looked for reasons to say YES! And looked for ways to convince their colleagues.

I spent a lot of time with these lawyers poring over tons of legal documents and such. Learning more about copyright and patent law than I ever wanted to. But united with a goal of making this happen.

These are the type of lawyers you want to work with.

Five years ago (long before I worked at Microsoft) I wrote a blog post titled Why Microsoft can't ship open source code which talks about some of the risks a company takes on in shipping code they didn't write:

To understand the code pedigree problem, let's talk about the nightmare scenario. Let's say Microsoft took my advice and shipped Paint.NET as a Windows Vista Ultimate Extra. Unbeknownst to Microsoft - or even the Paint.NET project leads - a project contributor had copied some GPL code and included it in a patch submission (either out of ignorance or as with malice aforethought). Two years later, a competitor runs a binary scan for GPL code and serves Microsoft with a lawsuit for copyright infringement. Microsoft is forced to pay eleventy bajillion dollars and damages. Perhaps even worse, they're hit with an injunction which prevents selling the offending application, which requires recalling shrinkwrapped boxes and working with computer vendors who've got the software pre-installed on computers in their inventory. All for shipping a simple paint program.

So, the risk is too great to justify the small reward.

The point is that, while there are obvious benefits to a company in shipping source code they didn't write, there are risks and costs. There's a good chance that your company doesn't open source all (or any?) of the software you write for these reasons. It's not necessarily because the company leadership / bosses / lawyers are stupid or bad, it's because it's a hard problem.

This doesn't even get into all the other costs, like the time and effort required to support (or continually explain why you don't support) unreleased code, review pull requests, move from systems that work really well internally to systems that are externally visible and accessible, move from source practices that have been optimized for a centralized team to an open source model, etc.

So I for one am profoundly thankful to all those who have done the work to get things worked out legally to both technically.

Where Next?

Lurking

The simplest way to take advantage of this is to watch changes on the live repository. It's easy to see what's being worked on by watching public pages:

Using

If you're interested in using code from the live repository, there are some directions here: http://aspnetwebstack.codeplex.com/documentation. A couple notes:

  • The directions show how to get the source code using a git client, which is a good idea if you're going to contribute back. If you just want to use the code, you can download a zip of the latest source (or any changeset) using the Download link on the Source Control tab.
  • Make sure you note the SkipStrongNames step which lets you run unit tests against delay-signed binaries.
  • If you're using Visual Studio 2010 SP1, the Runtime.sln handles package restore. If not, you'll need to follow the build.cmd directions to handle that.

Contributing

The first thing that often comes to mind when talking about contributing to an open source project is with surprise deliveries of random code. I've found - after having participating in a lot of open source projects - that is not the best way to get involved in any project. The team's listed some good ways to get started, including bug reports and contributing tests. I try to do this kind of thing on projects I'm getting started with - it's a good way to get familiar with the source code and the way the project's run, which is an important first step.

Miguel de Icaza has a great post on Open Source Contribution Etiquette which is great background on how to get started in contributing to a project.

If you want to contribute code, the team has listed some important steps. The whole list is important, but I want to point out one that thing - the Contributor License Agreement. It's a pretty short form (11-12 blanks to fill in, including date and signature) that essentially (I am not a lawyer) says who you are and that you're granting the rights to the code you're contributing.

Oh, and if you're interested in contributing to Mono, they're looking for some help in integrating this new code.

Exciting times!

ASP.NET Web API - Screencast series Part 6: Authorization

We're concluding a six part series on ASP.NET Web API that accompanies the getting started screencast series. This is an introductory screencast series that walks through from File / New Project to some more advanced scenarios like Custom Validation and Authorization. The screencast videos are all short (3-5 minutes) and the sample code for the series is both available for download and browsable online. I did the screencasts, but the samples were written by the ASP.NET Web API team.

In Part 1 we looked at what ASP.NET Web API is, why you'd care, did the File / New Project thing, and did some basic HTTP testing using browser F12 developer tools.

In Part 2 we started to build up a sample that returns data from a repository in JSON format via GET methods.

In Part 3, we modified data on the server using DELETE and POST methods.

In Part 4, we extended on our simple querying methods form Part 2, adding in support for paging and querying.

In Part 5, we added support for Data Annotation based validation using an Action Filter.

In Part 6, we'll require authentication using the built-in Authorization Filter.

[Video and code on the ASP.NET site]

Requiring Authorization using the Authorization Filter

In Part 5, we use a custom Global Action Filter to enforce validation on every Action. In this (final) part, we'll use the built-in Authorize Filter. As with other Filters, they can be applied at the Action, Controller, or Global levels. In this case, we'll add it at the controller level by adding the AuthorizationFilter attribute.

[Authorize] 
public class CommentsController : ApiController  
{ 
    ...
}

That's it from the server side. If a client makes an unauthorized request, the AuthorizationFilter does the only thing that makes sense for an HTTP API - it returns an HTTP Status Code 401, Authorization Required. Again, we're back to the value of using HTTP for an API - we don't need to arrange anything, any client on any platform will know what an HTTP 401 response means.

Handling Redirection on the Client

Many websites (and web frameworks) handle authorization by doing a server-side redirection to a login page. I wrote an in-depth post about how ASP.NET MVC handles authorization redirection - internally an HttpUnauthorizedResult (HTTP 401) is intercepted by the FormsAuthenticationModule, which redirects to Login URL specified in web.config.

None of that makes sense from an HTTP API perspective, though. HTTP API's return HTTP Responses to clients, which include things like Status Codes, Response Body, and Headers. It's up to the client to decide what to do when they get a 401. In this JavaScript / browser based sample, we'll just redirect to the login page on the client.

$(function () { 
    $("#getCommentsFormsAuth").click(function () { 
        viewModel.comments([]); 
        $.ajax({ url: "/api/comments", 
            accepts: "application/json", 
            cache: false, 
            statusCode: { 
                200: function(data) { 
                    viewModel.comments(data); 
                }, 
                401: function(jqXHR, textStatus, errorThrown) { 
                    self.location = '/Account/Login/'; 
                } 
            } 
        }); 
    }); 
});

In this case, logging in gives you a valid forms auth cookie, so your next request will pass authorization.

What about other validation scenarios?

If you want to do something different with validation in an ASP.NET Web API controller, usually the best approach is to create a custom Authorization Filter which derives from the base AuthorizationFilterAttribute and overrides the OnAuthorization method. Here a few blog posts showing how to extend authentication in ASP.NET Web API:

On the client, it's up to you. You may want to show a login form in a desktop application, handle things programmatically when accessing the service via code, etc. You'll follow the same pattern, though - handle the HTTP 401 status code and login to the server, either by posting to a login action or following the service's documented login API.

The End... and Where To Next

That wraps up this series. Some ideas of where to go next:

Posted by Jon Galloway | 44 comment(s)
Filed under: ,

ASP.NET Web API - Screencast series Part 5: Custom Validation

We're continuing a six part series on ASP.NET Web API that accompanies the getting started screencast series. This is an introductory screencast series that walks through from File / New Project to some more advanced scenarios like Custom Validation and Authorization. The screencast videos are all short (3-5 minutes) and the sample code for the series is both available for download and browsable online. I did the screencasts, but the samples were written by the ASP.NET Web API team.

In Part 1 we looked at what ASP.NET Web API is, why you'd care, did the File / New Project thing, and did some basic HTTP testing using browser F12 developer tools.

In Part 2 we started to build up a sample that returns data from a repository in JSON format via GET methods.

In Part 3, we modified data on the server using DELETE and POST methods.

In Part 4, we extended on our simple querying methods form Part 2, adding in support for paging and querying.

In Part 5, we'll add on support for Data Annotation based validation using an Action Filter.

[Video and code on the ASP.NET site]

Adding Validation Rules using Data Annotations

To start with, we add some validation rules to our model class using Data Annotations - Required and StringLength in this case.

[Required] 
public string Text { get; set; } 
 
[Required] 
[StringLength(10, ErrorMessage = "Author is too long! This was validated on the server.")] 
public string Author { get; set; } 
 
[Required] 
public string Email { get; set; } 

Writing an Action Filter that Enforces Validation Rules

In ASP.NET MVC, that would be it - the validation rules are enforced in controller actions, and automatically passed along as HTML5 data- attributes where they're handled via unobtrusive jQuery validation in the browser. ASP.NET Web API doesn't directly enforce those validation rules without a little more work, though. I think that might be because handling validation errors in an HTTP API isn't something you'd want to do automatically. Who knows, maybe they'll add that in later just to make me look dumb(er). But for now, it takes a bit of work to enforce those validation rules.

Fortunately, by a little more work I mean about 10-15 lines of code. It's easy to hook this kind of thing up using an ASP.NET MVC action filter. Action filters are really powerful, as they allow you to modify how controller actions work using the following methods:

  • OnActionExecuting – This method is called before a controller action is executed.
  • OnActionExecuted – This method is called after a controller action is executed.
  • OnResultExecuting – This method is called before a controller action result is executed.
  • OnResultExecuted – This method is called after a controller action result is executed.

You can apply an action filter attribute on specific actions, on an entire controller class, or globally. There are a few built-in action filters to handle common cases like custom authorization or error handling, and you can extend them if you need to handle a custom scenario.

ASP.NET Web API uses that same extensibility model via Filters. If you want ASP.NET Web API to do something that's not built in, the hook for that is very often to use an action filter. As with ASP.NET Action Filters, you can either extend on any of the in-built filters ( ResultLimit, AuthorizationFilter, ExceptionFilter) or write a custom ActionFilterAttribute.

public class ValidationActionFilter : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(HttpActionContext context) 
    { 
        var modelState = context.ModelState; 
        if (!modelState.IsValid) 
        { 
            dynamic errors = new JsonObject(); 
            foreach (var key in modelState.Keys) 
            { 
                var state = modelState[key]; 
                if (state.Errors.Any()) 
                { 
                    errors[key] = state.Errors.First().ErrorMessage; 
                } 
            } 

            context.Response = new HttpResponseMessage<JsonValue>(errors, HttpStatusCode.BadRequest); 
        } 
    } 
}

This is an OnActionExecuting filter, so it executes before the Action. It takes in the context (note - this is a System.Web.Http.Controllers.HttpActionContext, not an System.Web.HttpContext), which gives it access to ModelState as well as other contextual information about the request. It runs any custom logic, and has the option of directly returning the response - as it does in case validation fails.

So, at a high level, we just need to check if the model fails validation, and if so, return an appropriate response.

1. Checking Data Annotation validation rules

As mentioned earlier in the series, ASP.NET Web API uses the same model binding system that's been in ASP.NET MVC for a while, so it already knows how to check validation rules from data annotations. That makes this step really easy - we just check the context.ModelState to see if it's valid. If it is, we're done - let the Action do its work and return the result. If it fails, go on to step 2.

2. Packaging up validation errors for the client

A single request can fail multiple validation rules, so to return useful information to the client we need to package up the error information. We could build up a structured, custom error results object, but we'd be serializing it to JSON when we were done, so why not just start there? ASP.NET Web API includes some very useful JSON classes, including JsonObject. JsonObject allows us to work with a C# dynamic that will be serialized as a JSON object very easily.

3. Returning a useful error error response

Finally, when we're done wrapping up all the validation errors, we return a response to the client. We can use an HttpResponseMessage<JsonValue> to both return the results and set the HTTP Status Code (HTTP 400 Bad Request) in one line:

context.Response = new HttpResponseMessage<JsonValue>(errors, HttpStatusCode.BadRequest); 

You'll remember from earlier in the series that HTTP Status Codes are very important to HTTP APIs, and that by always setting the appropriate status code our clients (be they JavaScript, .NET desktop clients, iOS devices, or aliens who natively speak HTTP) will be able to understand responses without reading a bunch of API documentation. If a client makes a bad request, we'll tell them it was a bad request, and send along validation errors in JSON format in case they want specifics.

Registering a Global Filter

As with ASP.NET MVC filters, ASP.NET Web API filters can be applied at whatever level of granularity you'd like - action, controller, or globally. In this case, we'd like the rules to be enforced on all actions in the application. We can do that by registering a global filter. That's a one-line change - we add a call in our Global.asax.cs Configure method to register the new filter:

public static void Configure(HttpConfiguration config) 
{ 
    config.Filters.Add(new ValidationActionFilter()); 
 
    var kernel = new StandardKernel(); 
    kernel.Bind<ICommentRepository>().ToConstant(new InitialData()); 
    config.ServiceResolver.SetResolver( 
        t => kernel.TryGet(t), 
        t => kernel.GetAll(t)); 
} 

Handling Validation Responses in a JavaScript Client

In this sample, we're working with a JavaScript client. Just for the sake of beating a dead horse a bit more, I'll remind you that JavaScript is a browser is just one possible client.

To add handle validation failures, we need to include a case for HTTP Status Code 400 in our $.ajax() jQuery call.

$.ajax({ 
    url: '/api/comments', 
    cache: false, 
    type: 'POST', 
    data: json, 
    contentType: 'application/json; charset=utf-8', 
    statusCode: { 
        201 /*Created*/: function (data) { 
            viewModel.comments.push(data); 
        }, 
        400 /* BadRequest */: function (jqxhr) { 
            var validationResult = $.parseJSON(jqxhr.responseText); 
            $.validator.unobtrusive.revalidate(form, validationResult); 
        } 
    } 
}); 

Break the rules? Talk to the HTTP 400.

So here's how this looks in action - filling out the form with an Author name that exceeds 10 characters now gets an HTTP 400 response.

2012-03-23 15h40_12

The error message shown above - "Author is too long! This was validated on the server." - is perhaps a little too smug, but is derived from the JSON error information in the request body:

2012-03-23 15h42_51

Onward!

That wraps up our look at supporting Data Annotation based validation using an Action Filter. In Part 6, we'll finish off the series with a look at Authorization using the built-in Authorize filter.

Posted by Jon Galloway | 6 comment(s)
Filed under: ,

ASP.NET Web API - Screencast series Part 4: Paging and Querying

We're continuing a six part series on ASP.NET Web API that accompanies the getting started screencast series. This is an introductory screencast series that walks through from File / New Project to some more advanced scenarios like Custom Validation and Authorization. The screencast videos are all short (3-5 minutes) and the sample code for the series is both available for download and browsable online. I did the screencasts, but the samples were written by the ASP.NET Web API team.

In Part 1 we looked at what ASP.NET Web API is, why you'd care, did the File / New Project thing, and did some basic HTTP testing using browser F12 developer tools.

In Part 2 we started to build up a sample that returns data from a repository in JSON format via GET methods.

In Part 3, we modified data on the server using DELETE and POST methods.

In Part 4, we'll extend on our simple querying methods form Part 2, adding in support for paging and querying.

[Video and code on the ASP.NET site]

This part shows two approaches to querying data (paging really just being a specific querying case) - you can do it yourself using parameters passed in via querystring (as well as headers, other route parameters, cookies, etc.). You're welcome to do that if you'd like.

What I think is more interesting here is that Web API actions that return IQueryable automatically support OData query syntax, making it really easy to support some common query use cases like paging and filtering. A few important things to note:

  • This is just support for OData query syntax - you're not getting back data in OData format. The screencast demonstrates this by showing the GET methods are continuing to return the same JSON they did previously. So you don't have to "buy in" to the whole OData thing, you're just able to use the query syntax if you'd like.
  • This isn't full OData query support - full OData query syntax includes a lot of operations and features - but it is a pretty good subset: filter, orderby, skip, and top.
  • All you have to do to enable this OData query syntax is return an IQueryable rather than an IEnumerable. Often, that could be as simple as using the AsQueryable() extension method on your IEnumerable.
  • Query composition support lets you layer queries intelligently. If, for instance, you had an action that showed products by category using a query in your repository, you could also support paging on top of that. The result is an expression tree that's evaluated on-demand and includes both the Web API query and the underlying query.

So with all those bullet points and big words, you'd think this would be hard to hook up. Nope, all I did was change the return type from IEnumerable<Comment> to IQueryable<Comment> and convert the Get() method's IEnumerable result using the .AsQueryable() extension method.

public IQueryable<Comment> GetComments() 
{ 
    return repository.Get().AsQueryable(); 
} 

You still need to build up the query to provide the $top and $skip on the client, but you'd need to do that regardless. Here's how that looks:

$(function () { 
    //--------------------------------------------------------- 
    // Using Queryable to page 
    //--------------------------------------------------------- 
    $("#getCommentsQueryable").click(function () { 
        viewModel.comments([]); 
 
        var pageSize = $('#pageSize').val(); 
        var pageIndex = $('#pageIndex').val(); 
 
        var url = "/api/comments?$top=" + pageSize + '&$skip=' + (pageIndex * pageSize); 
 
        $.getJSON(url, function (data) { 
            // Update the Knockout model (and thus the UI) with the comments received back  
            // from the Web API call. 
            viewModel.comments(data); 
        }); 
 
        return false; 
    }); 
});

And the neat thing is that - without any modification to our server-side code - we can modify the above jQuery call to request the comments be sorted by author:

$(function () { 
    //--------------------------------------------------------- 
    // Using Queryable to page 
    //--------------------------------------------------------- 
    $("#getCommentsQueryable").click(function () { 
        viewModel.comments([]); 
 
        var pageSize = $('#pageSize').val(); 
        var pageIndex = $('#pageIndex').val(); 
 
        var url = "/api/comments?$top=" + pageSize + '&$skip=' + (pageIndex * pageSize) + '&$orderby=Author'; 
 
        $.getJSON(url, function (data) { 
            // Update the Knockout model (and thus the UI) with the comments received back  
            // from the Web API call. 
            viewModel.comments(data); 
        }); 
 
        return false; 
    }); 
});

So if you want to make use of OData query syntax, you can. If you don't like it, you're free to hook up your filtering and paging however you think is best. Neat.

In Part 5, we'll add on support for Data Annotation based validation using an Action Filter.

Posted by Jon Galloway | 3 comment(s)
Filed under: ,

ASP.NET Web API - Screencast series Part 3: Delete and Update

We're continuing a six part series on ASP.NET Web API that accompanies the getting started screencast series. This is an introductory screencast series that walks through from File / New Project to some more advanced scenarios like Custom Validation and Authorization. The screencast videos are all short (3-5 minutes) and the sample code for the series is both available for download and browsable online. I did the screencasts, but the samples were written by the ASP.NET Web API team.

In Part 1 we looked at what ASP.NET Web API is, why you'd care, did the File / New Project thing, and did some basic HTTP testing using browser F12 developer tools.

In Part 2 we started to build up a sample that returns data from a repository in JSON format via GET methods.

In Part 3, we'll start to modify data on the server using DELETE and POST methods.

[Video and code on the ASP.NET site]

So far we've been looking at GET requests, and the difference between standard browsing in a web browser and navigating an HTTP API isn't quite as clear. Delete is where the difference becomes more obvious. With a "traditional" web page, to delete something'd probably have a form that POSTs a request back to a controller that needs to know that it's really supposed to be deleting something even though POST was really designed to create things, so it does the work and then returns some HTML back to the client that says whether or not the delete succeeded. There's a good amount of plumbing involved in communicating between client and server.

That gets a lot easier when we just work with the standard HTTP DELETE verb. Here's how the server side code works:

public Comment DeleteComment(int id)  
{ 
    Comment comment; 
    if (!repository.TryGet(id, out comment)) 
        throw new HttpResponseException(HttpStatusCode.NotFound); 
    repository.Delete(id); 
    return comment; 
} 

If you look back at the GET /api/comments code in Part 2, you'll see that they start the exact same because the use cases are kind of similar - we're looking up an item by id and either displaying it or deleting it. So the only difference is that this method deletes the comment once it finds it. We don't need to do anything special to handle cases where the id isn't found, as the same HTTP 404 handling works fine here, too.

Pretty much all "traditional" browsing uses just two HTTP verbs: GET and POST, so you might not be all that used to DELETE requests and think they're hard. Not so! Here's the jQuery method that calls the /api/comments with the DELETE verb:

$(function() { 
    $("a.delete").live('click', function () { 
        var id = $(this).data('comment-id'); 
 
        $.ajax({ 
            url: "/api/comments/" + id, 
            type: 'DELETE', 
            cache: false, 
            statusCode: { 
                200: function(data) { 
                    viewModel.comments.remove( 
                        function(comment) {  
                            return comment.ID == data.ID;  
                        } 
                    ); 
                } 
            } 
        }); 
 
        return false; 
    }); 
});

So in order to use the DELETE verb instead of GET, we're just using $.ajax() and setting the type to DELETE. Not hard.

But what's that statusCode business? Well, an HTTP status code of 200 is an OK response. Unless our Web API method sets another status (such as by throwing the Not Found exception we saw earlier), the default response status code is HTTP 200 - OK. That makes the jQuery code pretty simple - it calls the Delete action, and if it gets back an HTTP 200, the server-side delete was successful so the comment can be deleted.

Adding a new comment uses the POST verb. It starts out looking like an MVC controller action, using model binding to get the new comment from JSON data into a c# model object to add to repository, but there are some interesting differences.

public HttpResponseMessage<Comment> PostComment(Comment comment)  
{ 
    comment = repository.Add(comment); 
    var response = new HttpResponseMessage<Comment>(comment, HttpStatusCode.Created); 
    response.Headers.Location = new Uri(Request.RequestUri, "/api/comments/" + comment.ID.ToString()); 
    return response; 
} 

First off, the POST method is returning an HttpResponseMessage<Comment>. In the GET methods earlier, we were just returning a JSON payload with an HTTP 200 OK, so we could just return the  model object and Web API would wrap it up in an HttpResponseMessage with that HTTP 200 for us (much as ASP.NET MVC controller actions can return strings, and they'll be automatically wrapped in a ContentResult). When we're creating a new comment, though, we want to follow standard REST practices and return the URL that points to the newly created comment in the Location header, and we can do that by explicitly creating that HttpResposeMessage and then setting the header information.

And here's a key point - by using HTTP standard status codes and headers, our response payload doesn't need to explain any context - the client can see from the status code that the POST succeeded, the location header tells it where to get it, and all it needs in the JSON payload is the actual content.

Note: This is a simplified sample. Among other things, you'll need to consider security and authorization in your Web API's, and especially in methods that allow creating or deleting data. We'll look at authorization in Part 6. As for security, you'll want to consider things like mass assignment if binding directly to model objects, etc.

In Part 4, we'll extend on our simple querying methods form Part 2, adding in support for paging and querying.

More Posts « Previous page - Next page »