MVC Security - Custom Implementation Of AuthorizeAttribute

In this post I will discuss some security related topics for ASP.Net MVC application. Authentication and Authorization are two basic pillars of a secure application. I will discuss how to handle Authorization using custom implementation of AuthorizeAttribute for MVC application.

AuthorizeAttribute

AuthorizeAttribute is a filter you can apply on a controller. What this means is that when a controller is executed, MVC framework will check for correct authorization for the request. Following code shows how you can apply default AuthorizeAttribute on a controller.

    [Authorize]
    public abstract class BaseController : Controller
    {....}
    

How does AuthorizeAttribute work

When AuthorizeAttribute is present on a controller, OnAuthentication will be called first. Default implementation of this method checks if authorization needs to be skipped or not. If it establishes that authorization needs to be performed, it will call AuthorizeCore method. Default implementation will check for following things to decide if request is authorized or not.

  • Is request authentication
  • If request is authenticated, it logged user present in list of authorized users if a list is provided when specifying AuthorizeAttribute.
  • If user is authorized, then it checks if user has one of the roles if a list of roles is provided in definition of AuthorizeAttribute.

All three conditions need to be satisfied for default AuthorizeCore method to vote Yes on authorization. If request is not authorized, then HandleUnauthorizedRequest method will be called to handle response for unauthorized request. Default implementation of this method will set result in context to HttpUnauthorizedResult. What this means is that MVC framework will send status code of 401 back and will trigger launch of login page is application is set to use forms authentication.

Custom AuthorizeAttribute Implementation

Default implementation for AuthorizeAttribute will suffice for some simple authorization of users. A lot of time you need to have some custom authentication and authorization which is not just covered by simply checking authentication or roles. For example you may want to redirect the user to a different page instead of redirecting to login page. For example you may want to send user to an area for which the user is authorized and not just send to login page. You do this my setting appropriate ActionResult in the Result property of context. Following code shows how to accomplish it.

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
  if (!filterContext.HttpContext.Request.IsAuthenticated)
  {
      var loginUrl = (new UrlHelper(filterContext.RequestContext)).
        RouteUrl(new { Controller = "Account", Action = "Login" });
      loginUrl = string.Format("{0}?reason={1}", loginUrl, _reason.Value);
      filterContext.Result = new RedirectResult(loginUrl);
  }
  else
  {
     //TODO: Request is authenticated, but something is causing authorization to fail. Need to
     //      add implementation for that check.
     base.HandleUnauthorizedRequest(filterContext);
   }
}
    

The following code shows some prototype implementation of AuthorizeCore method to set some fail reason that could be used down the line in request handling method.

protected override bool AuthorizeCore(HttpContextBase httpContext)
{
   var pass = base.AuthorizeCore(httpContext);
   if (!pass)
   {
     //TODO: Need to add implementation to establish reason for failure.
     _reason = 1;
   }
            return pass;
}
    

Skipping Authorization

Some time you have situation where AuthorizeAttribute is set on base class used for all controllers. But there are few controllers that do not need to be authorized. To deal with that situation, set AllowAnonymous attribute on that controller. This way when MVC framework executes OnAuthorization method, it will notice that attribute and skip calling of AuthorizeCore method. I have perfect case in my own application. I have established AuthorizeAttribute on base class. My AccountController is also derived from same base class. Now if I do not set AllowAnonymous attribute on Account controller then my application will end up in a loop. Following code shows how AllowAnonymous attribute is set in my application.

[SiteAuthorization]
public abstract class BaseController : Controller
{......}

[AllowAnonymous]
 public class AccountController : BaseController
{.....}
    

In upcoming blog discussion, I will discuss more about security in MVC applications.

comments powered by Disqus

Blog Tags