Web API 2 security extensibility points part 4: custom authorisation filters

Introduction

In the previous post we built a custom HTTP message handler for our demo Web API 2 application. We saw how a registered message handler intercepts all calls to your API before authentication filters are executed. We also wrote a couple of examples where we checked for the presence of a custom header and of an authorisation header. We finally showed how to set the principal for the current HTTP call.

In this post we’ll see another way you can intercept the calls to your API. Authorisation filters are executed after authentication filters and before your controller action methods. That is the last stage where you can add your custom auth-related logic.

Authorisation attributes in .NET

There are built-in authorization attributes in .NET MVC and Web API. First we have the Authorize attribute which you can apply at the controller or the controller action level. You can place an empty Authorize attribute in your controllers and its effect will be that the user of the incoming HTTP call must be authenticated. This attribute has an overloaded version where you can specify a certain Role the authenticated user must be a member of, like Authorize(Role = “Admin”). You can probably guess that the user of the HTTP call must be within the Admin role in order to reach the controller or one of its actions.

You can declare that a controller or an action method can be reached with an anonymous user using the AllowAnonymous attribute.

Custom authorization filters

Just like in the case of authentication filters it’s not a major deal to construct your custom authorisation filter. All you need to is derive from the AuthorizeAttribute class and override the IsAuthorized method. It returns a boolean where a “false” means that the user is not authorised. Make sure you derive from the AuthorizeAttribute in the System.Web.Http namespace which contains many of the Web API related classes. There’s an AuthorizeAttribute class in the System.Web.Mvc namespace as well but that’s meant to be used in MVC projects instead.

As a side note we can mention the virtual HandleUnauthorizedRequest method of AuthorizeAttribute where you can carry out some custom logic in case authorization has failed.

We already have a Filters folder from part 2 of this series. Let’s add a class called CustomAuthorizationFilterAttribute to that folder with that following implementation stub. The example shows how to access the principal of the HTTP call. We’ll return false so that we can check that HandleUnauthorizedRequest is also called:

public class CustomAuthorizationFilterAttribute : AuthorizeAttribute
{
	protected override bool IsAuthorized(HttpActionContext actionContext)
	{
		IPrincipal incomingPrincipal = actionContext.RequestContext.Principal;
		Debug.WriteLine(string.Format("Principal is authenticated at the start of IsAuthorized in CustomAuthorizationFilterAttribute: {0}", incomingPrincipal.Identity.IsAuthenticated));
		return false;
	}

	protected override void HandleUnauthorizedRequest(HttpActionContext actionContext)
	{
		Debug.WriteLine("Running HandleUnauthorizedRequest in CustomAuthorizationFilterAttribute as principal is not authorized.");
                base.HandleUnauthorizedRequest(actionContext);
	}
}

You can decorate the Get action method as follows:

[CustomAuthorizationFilter]
public IHttpActionResult Get()

Run the /customers endpoint and you should see the following debug output assuming you have the auth filter and the custom HTTP message handler registered in Global.asax:

Principal is authenticated at the start of SendAsync in CustomAuthenticationMessageHandler: False
Incoming principal in custom auth filter AuthenticateAsync method is authenticated: True
Incoming principal in custom auth filter ChallengeAsync method is authenticated: True
Principal is authenticated at the start of IsAuthorized in CustomAuthorizationFilterAttribute: True
Running HandleUnauthorizedRequest in CustomAuthorizationFilterAttribute as principal is not authorized.

We can see that the Get action is never reached as the user is not authorised to access it. If you change the return statement of IsAuthorized to “return true” then everything looks good again:

Principal is authenticated at the start of SendAsync in CustomAuthenticationMessageHandler: False
Incoming principal in custom auth filter AuthenticateAsync method is authenticated: True
Incoming principal in custom auth filter ChallengeAsync method is authenticated: True
Principal is authenticated at the start of IsAuthorized in CustomAuthorizationFilterAttribute: True
Principal authenticated from extension method: True
Principal authenticated from shorthand property: True
Principal authenticated from User: True

You can set the principal in the IsAuthorized method if you want:

IPrincipal genericPrincipal = new GenericPrincipal(new GenericIdentity("Andras", "CustomIdentification"), new string[] { "Admin", "PowerUser" });
actionContext.RequestContext.Principal = genericPrincipal;

In the next post which will finish this series we’ll investigate the basics of adding an OWIN middleware to perform your authentication logic.

You can view the list of posts on Security and Cryptography here.

About Andras Nemes
I'm a .NET/Java developer living and working in Stockholm, Sweden.

One Response to Web API 2 security extensibility points part 4: custom authorisation filters

  1. NetUser says:

    The entire area around AuthorizeAttribute no longer works as there isn’t a ‘IsAuthorized()’ method to override! (VS 2017), and they moved it all into Microsoft.AspNetCore.Authorization / NuGet package…

Leave a comment

Elliot Balynn's Blog

A directory of wonderful thoughts

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT TUTORIALS WITH OPEN-SOURCE PROJECTS

Once Upon a Camayoc

Bite-size insight on Cyber Security for the not too technical.