[EXTENSION] srbac : Web interface for the administration of rbac

This is a nice attempt at an extension, and appreciated, but some fundamental good programming practices are not followed.

The code relies on hard-coded mystery constants (e.g., 0, 1 and 2 for operations, tasks and roles) rather than naming them as constants. The types should ideally reference a lookup table as well, ensuring referential integrity.

I would recommend that you add:




  const TYPE_OPERATION = 0;

  const TYPE_TASK = 1;

  const TYPE_ROLE = 2;



to AuthItem.php, and reference those constants in the code. The same should be true for the status return values in Helper.php, SUCCESS, OVERWRITE and ERROR.

Line 400 in AuthitemController.php should be:


$criteria->condition = "1=1";

so that it will work with Postgres.

Thanks for your comments

The 0, 1 and 2 for operations, tasks and roles are the hard coded values used by Yii on CDbAuthManager so I didn’t mind change them.

The other codes should be changed




framework/web/auth/CAuthItem.php:	const TYPE_OPERATION=0;

framework/web/auth/CAuthItem.php:	const TYPE_TASK=1;

framework/web/auth/CAuthItem.php:	const TYPE_ROLE=2;



I have question is there any way to check if current user has access to action with given name?

For example I have "post/show" action and in "show" view i have form for comments, which is related with "comment/create" action. I want to know if current user is allowed to send comments so I could decide whether to display comment form or not.




<?php if(AuthItem::checkAccess(Yii::app()->user->id,'comment/create')): ?>

<div> <!-- Beggining of comment form -->

<!-- Comment form-->

</div> <!-- End of comment form -->

<?php endif; ?>



Try




<?php

if(Yii::app()->user->checkAccess('CommentCreate')): ?> // or whatever the authItem is named

<div> <!-- Beggining of comment form -->

<!-- Comment form-->

</div> <!-- End of comment form -->

<?php endif; ?>

?>



You are right

I had only checked the YII class reference

http://www.yiiframework.com/doc/api/CAuthItem#getType-detail

and not the code. ::)

Little OT here, but did you know that there’s actually a town in Bosnia called Srbac :) ?

http://www.srbac-rs.com/ (down at the moment)

btw: srbac is still working pretty flawless in my app.

cool:)) You’ll never know…

Greets

CoLT

Hey everyone,

I have just installed and configured in a new site srbac and works perfect, thx Spyros!!!

My little contribution to the cause:

Problem: to decide if show or hide links in menu I use CWebUser->checkAccess to check the operation, but it doesn’t work properly with srbac whitelist so I took part of your SBaseController code and made my replacement of CWebUser to integrate it with srbac

Solution: I have put this in protected/components




<?php

/**

 * Overrides CWebUser to use srbac authentication

 */

class SrbacWebUser extends CWebUser {


    public function checkAccess($operation,$params=array(),$allowCaching=true) {

        if (Yii::app()->getModule('srbac')->isInstalled()) {

            //Always allow access if $access is in the allowedAccess array

            if(in_array($operation, $this->allowedAccess())) return true;

            //Allow access when srbac is in debug mode

            if(Yii::app()->getModule('srbac')->debug) return true;


        }

        return parent::checkAccess($operation, $params, $allowCaching);        

    }


    /**

     * The auth items that access is always  allowed. Configured in srbac module's

     * configuration

     * @return The always allowed auth items

     */

    protected function allowedAccess() {

        Yii::import("srbac.components.Helper");

        return Helper::findModule('srbac')->getAlwaysAllowed();

    }

}



and added to my configuration:




                'user'=>array(

                        'class'=>'SrbacWebUser',

                        // enable cookie-based authentication

                        'allowAutoLogin'=>true,

                        'loginUrl'=>array('user/login'),

                ),



I hope it helps!!

Greetings from Spain,

Hwangar

One more thing I changed in your module

I wanted the srbac autodiscovery, that actually checks the action* methods in controllers could discover widget actions declared in method actions(), so I changed in method _getControllerInfo the last part (from "// $action == "actions"… process the method" on) to process such case

It’s working for me right now but it’s not tested, please check it!




  private function _getControllerInfo($controller, $getAll = false) {

    $actions = array();

    $allowed = array();

    $auth = Yii::app()->authManager;


    //Check if it's a module controller

    if(substr_count($controller, "/")) {

      $c = explode("/", $controller);

      $controller = $c[1];

      $module = $c[0]."/";

      $contPath = Yii::app()->getModule($c[0])->getControllerPath();

      $control = $contPath.DIRECTORY_SEPARATOR.str_replace(".", DIRECTORY_SEPARATOR, $controller).".php";

    } else {

      $module = "";

      $contPath = Yii::app()->getControllerPath();

      $control = $contPath.DIRECTORY_SEPARATOR.str_replace(".", DIRECTORY_SEPARATOR, $controller).".php";

    }


    $task =$module.str_replace("Controller", "", $controller);


    $taskViewingExists = $auth->getAuthItem($task."Viewing")!==null ? true : false;

    $taskAdministratingExists = $auth->getAuthItem($task."Administrating")!==null ? true : false;

    $delete = Yii::app()->request->getParam('delete');


    $h = file($control);

    for ($i = 0 ; $i < count($h) ; $i++) {

      $line = trim($h[$i]);

      if(preg_match("/^(.+)function( +)action*/", $line)) {

        $action = trim(substr($line, strpos($line, "action")));

        $patterns[0] = '/\s*/m';

        $patterns[1] = '/\(/m';

        $patterns[2] = '/\)/m';

        $patterns[3] = '/\{/m';

        $replacements[2] = '';

        $replacements[1] = '';

        $replacements[0] = '';

        $action = preg_replace($patterns, $replacements, trim($action));

        $itemId = $module.str_replace("Controller","",$controller).

          str_replace("action", "", $action);

        if($action !="actions" ) {

          if($getAll) {

            $actions[$module.$action] = $itemId;

            if(in_array($itemId, $this->allowedAccess())) {

              $allowed[] = $itemId;

            }

          } else {

            if(in_array($itemId, $this->allowedAccess())) {

              $allowed[] = $itemId;

            } else {

              if($auth->getAuthItem($itemId) === null && !$delete) {

                if(!in_array($itemId, $this->allowedAccess())) {

                  $actions[$module.$action] = $itemId;

                }

              } else if($auth->getAuthItem($itemId)!==null && $delete) {

                if(!in_array($itemId, $this->allowedAccess())) {

                  $actions[$module.$action] = $itemId;

                }

              }

            }

          }

        } else { // $action == "actions"... process the method

			if (is_file($control)) {

				if(!class_exists($controller,false)) require($control);

				if(class_exists($controller,false) && is_subclass_of($controller,'CController')) {

                    $tmp = array();

                    $controller_obj = new $controller($controller, $module);

                    $controller_actions = $controller_obj->actions();

                    foreach ($controller_actions as $prefix=>$act) {

                        $act_class_name = is_array($act) ? $act['class'] : $act;

                        $act_class=Yii::import($act_class_name,true);

                        $subaction_obj = new $act_class($controller_obj, ''); // Id not needed to invoke actions()

                        if ($act_class && method_exists($subaction_obj, 'actions')) {

                            $map=call_user_func(array($subaction_obj,'actions'));

                            if ($map) {

                                foreach ($map as $key=>$item) {

                                    $subaction = $itemId.ucfirst($prefix.$key);

                                    $actions[$module.'action'.$subaction] = $subaction;

                                    if(in_array($subaction, $this->allowedAccess())) {

                                        $allowed[] = $subaction;

                                    }

                                }

                            }

                        }

                    }

				}

			}

        }

      }

    }

    return array($actions,$allowed, $delete , $task, $taskViewingExists, $taskAdministratingExists);

  }



Hope it helps!

Hwangar

Thanks,

I’ll check it. This could also detect the captcha action (a problem many users have)

I just started experimenting with srbac, and I had some install trouble. A minor change I recommend is in views->authitem->install->el_gr->install.php, modify the file like this:

<div class="error">

          &lt;?php echo Helper::translate('srbac','srbac is not Configured');?&gt;


          &lt;?php echo &quot;&lt;pre&gt;&quot; . &#036;e-&gt;getMessage() . &quot;&lt;/pre&gt;&quot;; ?&gt;

</div>

The error message helped me solve the problem very much, and thanks for a wonderful module!

Thanks, I added it in the todo list

I am having a problem with the Autocreate AuthItems function and the URL creator in yii.

It seems that the urls generated by yiis components are note compatible with the authitems generated.

For instance the delete column in the gridview generates this url:

index.php?r=admin/productArea/delete&id=1

When clicking this while being logged in with a user that has access to all items i srbac i get an unauthorized message.

The controller is the folder controllers/admin/ it is named ProductArea and extends SBaseController, the function name is actionDelete - srbac generates this item: admin.ProductAreaDelete

I have the same problem with all other controllers in the admin subdirectory.

Has anyone had the same problem? Any quick fixes?

Hey Jens, I had the same problem and posted the solution three posts up. Although Spyros has to have a look at this, for me it’s working (with actions provided with captcha component and others from my own components)

Hope it helps

Hwangar

Hi jens, I created an admin subdirectory and checked a controllers actions with no problem. Please add an

echo $access;

in SBasecontroller’s before action function after

$access = $mod.$controller.ucfirst($this->action->id);

and check if admin.ProductAreaDelete is echoed.

Martin I checked your code and I have a problem with

method_exists($subaction_obj, ‘actions’) which returns false so no subactions are added in the actions array

At least the captcha action I checked is not show up (That’s because the $subaction_obj that’s the captcha class does not have an actions method)

Thank you for you quick response, figured it out now… stupid mistake on my behalf - had forgotten to delete the old authorization rules in the Controllers.

New question - whats the best way to redirect to the login page with an unauthrized message instead of just showing the default unauthorized view?

I tried switching this view to the login page but that just results in an error message.

Hello spyros,i was checking the srbac. When i click the install button from http://localhost/index.php?r=srbac/authitem/install i get the message that the installation was successfull but when i click to the link that suppose to get me to index.php?r=srbac/authitem/frontpage i get to install again.

Am i missing something?

Friendly,

dimitris (thessaloniki)

First check if the table names in the database are exactly the same as in the configuration (same case because some Databases convert the table names to lower case)

If the problem still exists let me know