4

Thinking about Access Control Lists bound to a web MVC architecture, I have a doubt on where the verification should be done.

Within Models? Controllers? FrontController?

Imagine a multiple module web application (like a website). I have a public site and a restricted admin zone.

  • All public site pages are acessible by anyone.
  • The restricted admin area is only accessed by an authenticated user.
  • There are some access levels for the users, such as root, admin and regular user.

I gave this some thought during my lunch time today and some ideas came out.

First, I needed to ask myself this question:

Is access control part of business logic?

After some time, I figure out that the answer should be no for most cases. Normally, for the situation I described, the business logic of the public area is about the same of the restricted one. When is not exact the same, what I normally do is to create a superset of both business logic rules, that contains all logic needed. So, even if there are several modules in my application, I normally have only one model layer.

Doing the ACL within my controllers leads to code duplication, since I'd have to check it everytime I'd need. Also, I'd get a high coupling between controllers and the ACL component.

Thinking about putting it inside FrontController seems to be the right approach. In deed, my initial thought was to put the ACL handler as a dependency for the FrontController.

This approach would have controller methods (actions) as resources of the ACL, creating roles for my users.

Some pseudo-code (mixing Java, C#, PHP):

aclHandler = new DefaultAcl();
aclHandler.addRole('none'); // not authenticated
aclHandler.addRole('user');
aclHandler.addRole('admin', extend='user');
aclHandler.addRole('root', extend='admin');

aclHandler.addUser('john', 'root');
aclHandler.addUser('mary', 'admin');
aclHandler.addUser('jane', 'user');

aclHandler.addResource('admin.content.create'); // MODULE.CONTROLLER.ACTION
aclHandler.addResource('admin.content.view');
aclHandler.addResource('admin.content.edit');
aclHandler.addResource('admin.content.remove');

aclHandler.addResource('public.content.view');

aclHandler.allow('*', 'public.*');

aclHandler.deny('*', 'admin.*'); // deny from all
aclHandler.allow('user', 'admin.content.view'); // allow user to view content
aclHandler.allow('admin', 'admin.content.{edit,create}'); // allow admin to edit and create content
aclHandler.allow('root', '*'); // root can do anything

This way, my FrontController would have something like:

class DefaultFrontController implements FrontControllerInterface {
    AclInterface acl {get};
    User currentUser {get;set};
    public DefaultFrontController(AclInterface acl, User user) {
        this.acl = acl;
        this.currentUser = user;
        // ...
    }

    public void dispatch(ControllerRequest request, ControllerResponse response) {
        try {
            this.acl.checkPrivileges(request.resource, this.currentUser);
        } catch (AclException e) {
            this.forbiddenAccessCallback(request, response, this.acl, this.currentUser);
            return;
        }

        // continue impl...
    }
}

fc = new FrontController(aclHandler, new User(name='John', role='root'));
fc.dispatch(...);  // ...

This implementation makes an ACL component a mandatory parameter for the FrontController constructor, so, now it's part of its state. This could be a problem when I don't need an ACL, but can be overpassed by creating a mock implementation of ACL component, like AllowFromAllAcl, that would allow any users to do anything.

Any ideas? Corrections? Suggestions?

3
  • 1
    Why is access control not part of the business logic? Commented Feb 19, 2014 at 18:47
  • Isn't the ACL dead? vimeo.com/2723800 Commented Feb 19, 2014 at 21:20
  • I can't watch it by now, but Zed Shaw is a kind of radical in some things. In his "Learn C the hard way" book, he says he'd rather have labels with error treatment and access them with goto than use exceptions. But enough of ad hominem. I'll see the video first. Commented Feb 20, 2014 at 1:20

2 Answers 2

7

Access control is part of business logic. If you look at use cases, or even user stories, you will see that there are actors involved in any business process. The access control lists are a method to ensure that all and only the actors CAN be involved with the business process.

Access control needs to be supported in the model, the view and the controller.

Access control is part of the model: By limiting the ability to change or view columns or records per the business logic, you necessarily prevent many failures. If only system administrators can change a secondary key field, then it won't be accidentally changed because someone implemented a form incorrectly. Now, I also suggest that you don't specify the restriction as based on "system_administrator" privilege but rather "change_secondary_key" privilege, which system_adminstrators have by design. This separates role from function.

Access control is part of the view. By not enabling form fields to edit data for which the person doesn't have the privileges, you prevent both confusion and errors.

Access control is part of the controller. The controller adjusts the page flow to present only the information appropriate to the user at a time and place that is appropriate.

Certainly, you want to have central management of access controls, on the principle of DNRY (Don't Needlessly Repeat Yourself). Access control is a cross-cutting concern.

4
  • But with the architecture I'm used to, there's no way of an user alter the model without passing through a Controller action. Commented Feb 20, 2014 at 1:23
  • @HenriqueBarcelos if your access control is only in the controller, you'll have to reimplement it when your ui changes from mvc to something else.
    – Andy
    Commented Feb 20, 2014 at 2:44
  • Actually I don't have anything implemented yet, just gathering some ideas. The way I'm planning, my ACL is architecture independent, it can be bound to any layer. I'm just asking which layers in a MVC architecture should depend on the ACL component. Commented Feb 20, 2014 at 11:20
  • 3
    I'm sure that I made myself clear. It has to be in all of them, just to different purpose. There is nothing more stupid than an application that allows you to fill in a form, click the Save button, and gives you an error message: "You aren't authorized to do that." (Edit: I take that back. There are things more stupid. However, this example ranks really high on the frustration index.) Commented Feb 20, 2014 at 12:53
-1

Generally speaking, this sort of thing is built into MVC.

Adding an "Authorize" attribute to a controller class, restricts access to all methods of the controller to "Must be logged in". Adding Authorize(Roles="Admin") to specific controller methods further restricts access to that route to an authenticated user with Admin roles assigned to them.

There are a couple of built-in authentication mechanisms in MVC, including windows Forms, Basic, etc, as well as a few that can be easily enabled with nuget packages such as Oauth etc.

If you need a more custom authentication method, you can derive from the Authorize attribute, and add it to your global configuration. Another method I've used in the past when working with a custom REST api type scenario, is to add an "ActionFilter" that executes before calling the route on the controller.

More information: http://msdn.microsoft.com/en-us/library/ff398049(v=vs.100).aspx http://www.dotnetcurry.com/showarticle.aspx?ID=957

Related Stack Overflow: https://stackoverflow.com/questions/18594316/custom-authentication-and-asp-net-mvc

Plenty of other information out there, just do some googling.

Around where to put your actual authentication logic, generally you will need to query users and roles from somewhere, if a custom scenario, add this logic to your data access layer, add sort of an "AuthorizationService" to your business logic, and consume it through your custom authorize attribute/filter.

4
  • 1
    If you do as you suggest, you lose or reimplement your authorization logic when you change to another ui framework. Ive done this a few times, winforms to wpf and webforms to mvc.
    – Andy
    Commented Feb 20, 2014 at 2:46
  • I actually do this way currently (more or less), but I'm not very satisfied. It's kind of inflexible. Commented Feb 20, 2014 at 11:23
  • @Andy That's entirely up to you. If your properly separating your concerns, all the custom Authorize Attribute is doing is getting it's information from your business logic (ie which user is it, and what access/roles does he/she have), then when you switch to a different UI framework, it's a minor task to integrate the same business logic in a new way. Authorization is a cross cutting concern, and coupling it tightly to your business logic can cause pain if you wish to reuse that logic in a different way/application later. Commented Mar 14, 2014 at 21:40
  • @MitchellLee, if you are developing an MVP (Model View Presenter) application Custom Authorization Attribute should be pain full. ACL with Authentication Proxy Pattern is the way I'm trying to implement. With this approach we can build a dynamically created/assigned role can validate easily. Commented May 11, 2021 at 7:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.