RBAC with CAccessControlFilter

admin: Thread Split from http://www.yiiframew…opic,191.0.html

Sorry that I continue this discussion in doc thread …

Now we can use RBAC with CAccessControlFilter so there is no problem to use it with ips, verbs, etc (I know that this can be also done by bizrule).

For example:



            array('allow',


                'actions'=>array('delete'),


                'roles'=>array('admin'),


                'ips'=>array('10.0.0.1'),


            )


I mean that such a method ([tt]checkActionAccess()[/tt]) would be much more flexible regardles of using RBAC.

It wolud also help in further development of application for example when will be need to introduce RBAC.  I mean situation when we use user rule for controling access and when application becomes bigger we need to introduce RBAC, so we change only rules in conrtoler from 'user' to 'roles'  and everything would work OK without any other changes in controler or views.

Without checkActionAccess() method we have to change all views or all controler methods such a  [tt]canUpdatePost()[/tt],

Of course we can use [tt]checkAccess()[/tt] but it's not affected by rules defined in controler. When using it we have to define

(role or task or operation doesn't matter) <------> (action)

assingment at least twice (in controler and in view) so it can results in mistakes when there are many actions and roles.

e.g.



$this->widget('application.components.ActionMenu',array(


    'items'=>array(


        array('label'=>'Update post',


           'url'=>array('post/update'),


           'visible'=>Yii::app()->user->checkAccess('?.... // here we have to think how it was defined in controler maybe it was moderator, or maybe updateOwnPost ??


        array('label'=>'Update post',


           'url'=>array('post/update'),


           'visible'=>=>Yii::app()->user->checkActionAccess('update'); //  - no problem .





IMHO there is few kinds of application where we can use username based accessControl. Most of them will need RBAC unless we treat username as a role (but this is not very good solution), so i think that idea or [tt]checkActionAccess()[/tt] is not so bad.

I agree that checkActionAccess can be convenient in many scenarios.

So how would you specify which actions can be accessed by which users? Managing or specifying these permission assignment is the most complex part.

In exactly same way as it is done in CAccessControlFilter - using CControler->rules().

It's off the top of my head so I'm not sure if I'm right.  In CControler:



function checkActionAccess($action) {


  $filter = new CAccessControlFilter;


  $filter->rules() = $this->accessRules();


  return $filter->preFilter(new CFilterChain('', $action));


}


Rest will be done by authManager when using RBAC and roles from rules  or other rules would be checked If not.  Am I right ?

I think your approach should work, but it is not very appropriate to include it in CController for the following reasons:

  1. It only applies to the same controller. It is often needed to check access of actions belonging to a different controller.

  2. It is difficult to specify additional conditions when checking the access. For example, how to check if a user can update a post based on the ownership?

  3. The performance is very bad the checking would go through the validation rules. (it is fine this is done only once, but when this is done many times in a view, performance has to be taken into consideration).

For these reasons, I think it is more appropriate to leave this implementation to developers. Of course, in order to reuse the same logic, we could come up with some helper component (and release as an extension) to do this job.

What do you think?

  1. You're right. Maybe it could be in CWebUser and then checkActionAccess($controler, $action). But in this case rules array of each requested controler should be cached in CWebUser for performance.

Anyway I think that checking access for another controllers is ussualy so rare or so obvious that for this we can use checkAccess().

  1. When using RBAC via bizRule.

  2. It can be cached… in the simpliest way in a class variable or method static variable:



function checkActionAccess($action) {


  static $actionAccessCache;


  if(!isset($actionAccessCache[$action]) {


    $filter = new CAccessControlFilter;


    $filter->rules() = $this->accessRules();


    $actionAccessCache[$action] = $filter->preFilter(new CFilterChain('', $action));


  }


  return $actionAccessCache[$action];


}


At the moment I see only one main goal of this method - to check whether to display link to action for the current controler or not (e.g. in controlers "submenu").  For other links on "higher level" like main menu or actions for other controllers I think that current checkAccess() is good enough.

As I correctly understand checkAccess can check permition not only for operation but also for task and role ?

You are the main developer of this project,  so you decide what to do with this. I just want to help :) 

I don’t have access to action decision, thats not assigned to my role ;)

Yeah, thank you for discussing these interesting topics, which drives the development of Yii.

I still feel it's a bit messy by including checkActionAccess() in either controller or CWebUser. Its functionality is mostly covered by checkAccess() already. So let's keep this in mind and see if more users want this feature.

Also thank you.

Now I'm preparing to create jQuery DataGrid (jqGrid) widget. I know that it should get CModel as a parameter, but I don't know yet how to create actions for it. I think that db operations shouldn't be performed in view were widget takes place. This actions should be in controller and returning some json data… but how to encapsulate it in to an extension … maybe it can be widget with CAction's ?

Good luck on next Saturday.

Good to hear you are working on a datagrid.

Because I am not very clear about the control and data flow with your datagrid, my comments below may not be correct.

  1. The datagrid should be created as a widget.

  2. Define a data property for the widget. Setting this property would populate the datagrid with the needed data.

  3. Define some events, such as onPrepareData, which are triggered by the widget when it needs to retrieve data. Developers should attach appropriate event handlers when using the widget so that they can supply the needed data to the datagrid.

  4. The datagrid view should contain some buttons which can submit to the same controller action (either via normal POST request or AJAX post request). The datagrid widget then checks to see if one of the button is submitted and triggers the corresponding event defined in 3.

I guess we should create a new thread to keep on discussing about this.

I would also add to topics.auth guide that the way to change "default" policy in accessControl from "allow" to "deny" is to set last rule:



array('deny'),


It maybe obvious, but default policy (when non of rules match) is "allow" which is not what we always want.

Thanks for the suggestion. Doc updated.

I know how to check for Access control. I couldnt find how to set roles.

Can anyone inform me please

I think the roles could come from the database