Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authorize attribute in MVC order, priority and function question

There is something in the roles I don't exactly get. using the [Authorize] attribute

When you have the [Authorize] attribute on the controller and on the action:

  1. When a role is in both, this role will have access
  2. When a role is only defined at the Controller, but not at the Action, no access
  3. When a role is only defined at the Action, but not at the Controller, no access

I get that, that's logical. You need access to the controller before you can run an action.

What I dont get is why this doesnt work:

[Authorize(Roles = "Algemeen Beheer, Admin, Coordinator, Secretariaat")]
public class FacturatieGegevensController : Controller {

    [Authorize(Users = "Stefan.coordinator", Roles = "Algemeen Beheer, Admin")]
    public ActionResult Create(int instID) {

        return View();
    }

}

When I am logged in as user Stefan.coordinator which has the role coordinator, I can access the controller, but I can not access the Create Action. I thought this would be an OR relation between Users and Roles. Is it not? and how do I get this to work?

like image 404
Stefanvds Avatar asked Oct 13 '22 18:10

Stefanvds


1 Answers

The condition to access the Create method is:

((ROLE in { Algemeen Beheer, Admin, Coordinator, Secretariaat })) [from controller-level] AND ((USER in { Stefan.coordinator }) AND (ROLE in { Algemeen Beheer, Admin })) [from method-level]

Once all the ANDs / ORs have been worked out, this results in simply:

USER in { Stefan.coordinator } AND ROLE in { Algemeen Beheer, Admin }

That is, within a particular AuthorizeAttribute, the Users and Roles are ANDed together. And across multiple AuthorizeAttributes, the conditions are ANDed together.

The best way to think of this is that the [Authorize] attributes are not aware of each other, so each executes independently. The controller-level one goes first, then the method-level one goes. To get access to the method, you need to pass all gates.

Edit - there was a question on how the logic works out as it does above.

Let:

A = ROLE is "Algemeen Beheer"
B = ROLE is "Admin"
C = ROLE is "Coordinator"
D = ROLE is "Secretariaat"
E = USER is "Stefan.coordinator"

Since the controller-level [Authorize] attribute is (A || B || C || D), the method-level [Authorize] attribute is (E && (A || B)), and multiple [Authorize] attributes are represented by a logical AND, the logic ends up as (A || B || C || D) && (E && (A || B)), which reduces to E && (A || B), which requires the user to be named "Stefan.coordinator" and to be in the "Algemeen Beheer" or "Admin" roles. Since the user Stefan.coordinator isn't in either of these two roles, the check fails.

To your particular problem..

If you want to apply your own logic to the [Authorize] attribute checks, subclass AuthorizeAttribute and override the AuthorizeCore method. That way you can say if (User == "Stefan.coordinator" || base.AuthorizeCore(...)) { ... }.

like image 119
Levi Avatar answered Oct 18 '22 02:10

Levi