-1

I'm working on a custom framework strictly for fun and educational purposes. I've read over this question on how to implement permissions and I like the answers; either using a decorator pattern and / or checking permissions based on the URL from a dispatcher.

My question is how the white list of permissions should be generated? I don't want every method in my controllers to require permission to execute, so I could, for example, use a special naming convention such as preceding method names with an "x":

class CalendarController
{
    public function index($year = null, $month = null, $day = null)
    {
        // display calendar (no permission needed)
    }

    public function xAddEvent()
    {
        // display form to add event (permission required)
    }

    public function xAddEventSubmit()
    {
        // submit form to add event (permission required)
    }
}

I could then write a script to iterate through all of my controllers and return the x-methods, giving me my list of permissions to assign to different roles.

Another option could be to hard-code permissions as a property of each controller, for example:

class CalendarController
{
    public $permissions = array('addEvent',
                                'addEventSubmit');

    public function index($year = null, $month = null, $day = null)
    {
        // display calendar (no permission needed)
    }


    public function addEvent()
    {
        // display form to add event (permission required)
    }

    public function addEventSubmit()
    {
        // submit form to add event (permission required)
    }
}

Are there any better alternatives or am I on the right track?

Community
  • 1
  • 1
mister martin
  • 6,197
  • 4
  • 30
  • 63
  • @tereško I linked to that very article in the first paragraph. It does not address my question. – mister martin May 03 '13 at 11:27
  • Sorry .. missed that. Though, both of your examples seem to relay on placing the burden of ACL on your controllers anyway. The access rights should be stored outside of your controllers. I would go with some "config/permissions.php" file. Keep in mind also that in some systems you need to provide GUI (like in different CMSs) for managing some of those permissions. – tereško May 03 '13 at 11:58
  • @tereško yes, that is precisely what I'm trying to do. I want to generate a list of permissions for my administration page. The question is how to generate that list in an efficient manner. The reason I'm leaning towards crawling the controllers is to avoid hard-coding the permissions elsewhere. The "roles" will be stored in a database, but the "permissions" attached to those roles is what I'm trying to list here dynamically. – mister martin May 03 '13 at 12:46

3 Answers3

1

Have you thought of method overloading? This is a very simple example. Basically, if a function is not found, the __call() function is used to catch it. Then, you can do your permission checks and call the correct private or protected method.

class CalendarController
{
    public function index($year = null, $month = null, $day = null)
    {
        // display calendar (no permission needed)
    }

    public function __call($name, $arguments)
    {
        // do your permission checks here
        if ($name == 'addEvent' && $this->hasPermission()) {
            return $this->_addEvent($arguments);
        }

        return false;
    }

    protected function _addEvent($params) {

    }
}
jon__o
  • 1,509
  • 13
  • 14
1

Note: this will be mostly an expansion on the solution that i provided in the linked article. I will not comment on answers from hakre.

As I understand your question, the issue basically is that you do not want to set access rights for each method separately.

Option 1: don't decorate

In the solution, that involves Decorator, one of the benefits is that, when you use the secured class (for example the Controller, though it can be any part of application), you do not need to know that it has been decorated. Therefore, if you have some controllers that should be fully accessible to anyone, then you can just not decorate those.

This approach would most likely require the factory, that is responsible for instantiation of controller, to have some list of controller that should or should-not be wrapped in a decorator. Since this would always require an if statement to consult the list, I personally would consider this only for instances on which you call more the one method (which, in my case, would exclude controllers).

Option 2: wildcards and whitelists

A different way tackle this would be take advantage of how you actually check for authorization.

$command = [ get_class($this->target), $method ];

This was the token, that get checked against. This means that the ACL receives not only the name of method, but also the full class name (including namespace, btw). It gives you an opportunity to create a list of rules that include both name of the class and method. Something along the lines of:

Controllers\Identification::*  anonymous
Controllers\*::*               admin
Controllers\Users::view        authenticated
Controllers\Users::remove      manager
Controllers\Users::add         manager

The idea is that you save some configuration where you define all the allowed interactions. The ACL goes down the list, checking the user's group, and on first match returns the result (in the example the admins can access everything except login page, which is allowed only for unauthenticated users). Then again, this particular example would depend on you implementing at least partial groups-contain-groups functionality.

I would also reiterate, that you should only use white-lists for this. There is no significant risk added, if you forget to allow managers to remove users, but, if you forget to deny users to remove other users, it can be a critical mistake when using blacklist based authorization.

my two cents

Community
  • 1
  • 1
tereško
  • 58,060
  • 25
  • 98
  • 150
0

I would recommend looking at other frameworks to get an idea of how they implement restrictions. For example, yii implements access restrictions based on the specific action requested and whether or not the user has a specific level of permissions. I would highly recommend RBAC (http://en.wikipedia.org/wiki/Role-based_access_control)

Yii example:

public function accessRules()
{
    return array(
        array('allow',  // allow all users to perform 'list' and 'show' actions
            'actions'=>array('list','show'),
            'users'=>array('*'),
        ),
        array('allow', // allow authenticated user to perform 'create' and 'update' actions
            'actions'=>array('create','update'),
            'users'=>array('@'),
        ),
        array('allow', // allow admin user to perform 'admin' and 'delete' actions
            'actions'=>array('admin','delete'),
            'users'=>array('admin'),
        ),
        array('deny',  // deny all users
            'users'=>array('*'),
        ),
    );
}

They also implement filters which tell us that certain actions must be requested with certain types of HTTP requests. the following example states that in order to run a create action, the HTTP request must be a POST.

public function filters()
{
    return array(
        'accessControl', // perform access control for CRUD operations
        'postOnly + create', // we only allow create via POST request
    );
}

Resource: http://www.larryullman.com/2010/01/14/yii-framework-access-control-lists/

Also see: http://www.yiiframework.com/wiki/169/configuring-controller-access-rules-to-default-deny/

Kevin
  • 523
  • 4
  • 20
  • What's wrong with this answer? Care to elaborate the problem you see? – Kevin May 03 '13 at 15:28
  • I personally didn't downvote your answer, but in either case it doesn't specifically address my question. – mister martin May 03 '13 at 18:17
  • I'm not asking how to implement a permissions system, I'm asking for recommendations on generating a dynamic list of permissions based on existing methods. – mister martin May 03 '13 at 19:18
  • 1
    These functions would go in your Controller classes. They define allowed actions on a per role basis. If you want one specific controller's permissions, you check the accessRules(). If you want all of your controller's actions check that it implements the base class, and merge the accessRules() arrays. Maybe I'm misunderstanding still somehow. Good luck to you. – Kevin May 03 '13 at 19:38
  • 2
    -1: What you are suggesting would essentially violate OCP. Look up what controller's responsibilities are (like in wikipedia, not in some crappy framework's doc). Controller is **NOT** responsible for dealing with user access management. – tereško May 04 '13 at 19:28
  • @metal_fan , well .. have you actually looked at how [CakePHP](http://book.cakephp.org/2.0/en/tutorials-and-examples/simple-acl-controlled-application/part-two.html) implements it? As for CodeIgniter - it does not come any structures for managing authorization. But the 3rd part implementations all follow the same blueprint - put it in the controllers, which is quite dreadful. – tereško May 06 '13 at 12:56