Skip to content

Beware the combined authorize filter mechanics in ASP.NET Core 2.1

July 15, 2018

In ASP.NET Core 2.1 one of the security changes was related to how authorization filters work. In essence the filters are now combined, whereas previously they were not. This change in behavior is controlled via the AllowCombiningAuthorizeFilters on the MvcOptions, and also set with the new SetCompatabilityVersion API that you frequently see in the new templates.

Prior to 2.1 each authorization filter would run independently and all the authorization filters would need to succeed allow the user access to the action method. For example:

[Authorize(Roles = "role1", AuthenticationSchemes = "Cookie1")]
public class SecureController : Controller
    [Authorize(Roles = "role2", AuthenticationSchemes = "Cookie2")]
    public IActionResult Index()
        return View();

The above code would trigger the first authorization filter and run “Cookie1” authentication, set the HttpContext’s User property with the resultant ClaimsPrincipal, and then check the claims for a role called “role1”. Then, the second authorization filter and run “Cookie2” authentication, overwrite the HttpContext’s User property (thus losing the “Cookie1” user’s claims) with the resultant ClaimsPrincipal, and then check the claims for a role called “role2”. In short, the user had to have both cookies to be granted access. Also, as side effect of this is also that in the action method, the code would only see the claims from “Cookie2”.

With the new compatibility changes in 2.1, the behavior of the above authorization filters has changed. The mechanics are that the authorization filters are now combined (somewhat). The roles are still kept separate, meaning the user must still have both “role1” and “role2”. But the surprising change is that now instead of both schemes being required, now only one is.

What happens is that both “Cookie1” and “Cookie2” are authenticated (if present) and the resultant claims are combined into the one User object. Then the checks for both “role1” and “role2” are done. So if both roles were only in one cookie, then access would be granted. And, of course, in the action method the combined claims from “Cookie1” and “Cookie2” would be available.

This is a different semantic that the way things previously worked. In essence your authorize filter requirements might be relaxed due to the presence of other authorize filters in the action method invocation hierarchy.

A scenario would this might be a issue is where you have an app that has both UI and APIs. A common technique is to use a global filter as a blanket protection to requires that all users be authenticated in the rest of the app:

services.AddMvc(options =>
   var policy = new AuthorizationPolicyBuilder()
   options.Filters.Add(new AuthorizeFilter(policy));

And then an API action method like this:

[Authorize(AuthenticationSchemes = "Bearer")]
public IActionResult PostData()

This new behavior opens us up to possible XSRF attacks on our APIs, whereas pre-2.1 the explicit authentication scheme on the action method protected us.

Now of course, policy schemes (aka virtual schemes), which are also new in 2.1, could help us address this, but that’s a design change in your app.

I agree with the suggestion by Microsoft in the docs that for this new feature:

We recommend you test your application using the latest version (CompatibilityVersion.Version_2_1).

But not so sure about their other comment:

We anticipate that most applications will not have breaking behavior changes using the latest version.

So, beware the side effects of the new combined authorization filter behavior in ASP.NET Core 2.1.

2 Comments leave one →
  1. July 16, 2018 2:36 am

    Reblogged this on

  2. July 16, 2018 6:51 am

    Good read, very informative, thanks

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: