Page 1 of 1

groups of permissions

PostPosted: Tue Mar 20, 2012 7:04 am
by Jean
Hi Steve and All,
I have created groups or profiles to set up permissions. My aim is to change the view in several specific tables according to the profiles and to set up the permissions to modify or delete records according to the groups, the user belongs to.
So I began creating several columns in the users tables groupe1, ..., groupe4 related to the groupes tables. Eventually I created a permission for each group like MIAL, ARBIZON, the normalized name of groups with capitals and underscores.
In the permissions.ini file I added
Code: Select all
[USER extends USER]
new=1
edit=1
[MIAL extends USER]
[ARBIZON extends USER]...


Then in the DelegateClass, i bound the permission to the first group (groupe1). Here I plan to hve it like a basis. I inserted :

Code: Select all
if (!isset($user) )        {
       return Dataface_PermissionsTool::NO_ACCESS();
       }
else {
    $groupe1 =  $user->val('groupe1');
if ($groupe1>0){
       $sql = "select permission FROM groupes WHERE id_groupes==$groupe1";
$res = @mysql_query($sql, $this->app->db());   
       $rang=mysql_fetch_row($res);
       $permission=$rang['permission'];
       return Dataface_PermissionsTool::getRolePermissions($permission);
      }
}...


Well now I am stuck because every user may belong to several groups and have permission profiles according to these groups.
Besides, each profile sees different records in the table.

Help!

Jean

Re: groups of permissions

PostPosted: Tue Mar 20, 2012 3:55 pm
by shannah
A couple of comments:

1. The getPermissions()/getRoles() methods need to be as lightweight as possible because they may be called hundreds of times per request. Running a mysql query inside it will slow things down drastically. Best to perform necessary queries in such a way that you can perform them once, then cache the results- then only access the cache on subsequent invocations. In your case you could easily calculate the group permissions for the current user once at the beginning of the request, then just access the cached values from the getPermissions() method.

2. I'm not sure that this approach is nuanced enough to capture the dynamic range of permissions that could be assigned a user. It looks like you are assigning permissions based on membership in groups - so the user will have the same permissions for every record of every table. You could overcome this problem by assigning permissions in your groupes table according to the table or record id. But things start to get much more complex very quickly when you do this.

-Steve

Re: groups of permissions

PostPosted: Wed Mar 21, 2012 12:48 am
by Jean
Thank you Steve, I think I will create a dashboard with a set of links for each user to simplify and follow your advices about the cache.
Now I see my app more clearly.

Have a nice day
Jean

Re: groups of permissions

PostPosted: Wed Mar 21, 2012 9:32 am
by shannah
I just want to make sure I don't cause any confusion with my comment about caching. I just mean that any query that you use inside the getPermissions() method should be called once per http request (not necessarily per session).

e.g. The wrong way.

Code: Select all
class tables_mytable {
function getPermissions($record){
     // do some stuff
     $res = mysql_query("select * from foo where bar=1");
     // do some stuff with the results
} // end getPermissions()
} // end tables_mytable


A beter way
Code: Select all
class tables_mytable {

    private $cachedPerms = null;
    private function _getCachedPerms($param1, $param2, ..., $paramN){
        if ( !isset($this->cachedPerms) ) {
            $this->cachedPerms = array();
            // do some stuff
            $res = mysql_query("select * from foo where bar=1 and param2='".addslashes($param2)."'");
            while ( $row = mysql_fetch_assoc($res) )  $this->cachedPerms[$row['fooid']] = $row;
        }
        return $this->cachedPerms;
    }

    function getPermissions($record){
        // do some stuff
        $perms = $this->getCachedPerms($param1, $param2, ..., $paramN);
        return $perms;
    }
}


In the latter case getPermissions() will run a db query on its first request, but subsequent requests will just load the cached value.

Re: groups of permissions

PostPosted: Thu Mar 22, 2012 12:51 am
by Jean
Thank you Steve,

I added it in the wiki.
Just a last question :
Outside cached permissions, is it possible to change permissions for a user according to query params in the URL ?

Have a nice day
Jean

Re: groups of permissions

PostPosted: Thu Mar 22, 2012 10:15 am
by shannah
Absolutely. The query parameters in the URL won't change during the course of a request. So it is still valid to cache permissions for the request when you perform calculations based on the query parameters.

Just be alert when making permissions depend on query parameters, because users shouldn't be able to get around permission restrictions by tinkering with query parameters.

-Steve

Re: groups of permissions

PostPosted: Fri Mar 23, 2012 3:16 am
by Jean
Thank you Steve,
I would need a documentation to understand how cachedPerms operates. How it interacts when you insert it at application level and table level.
Is it related with output_cache ?
Jean

Re: groups of permissions

PostPosted: Fri Mar 23, 2012 12:42 pm
by shannah
Hi Jean,

No this isn't related to the output cache. I think you may have the impression that it is more complicated than it is. When I say "cache", I mean that expensive operations like database queries should have their results saved in a variable for later use. Then when the output is required at a later part of the request, you can just access the variable that holds the results, rather than performing the same query again.

E.g.


The following doesn't cache the results of the query in the getUsers() method. If the method is called 100 times in the request, the database will be hit by 100 of the same query. This is slow.

Code: Select all
class UserTool {

    function getUsers(){
        $out = array();
        $res = mysql_query("select * from users");
        while ($row = mysql_fetch_object($res)) $out[] = $row;
        @mysql_free_result($res);
        return $out;
    }
}


The following implementation will scale much better because the results of the query are cached the first time it's run so subsequent calls to getUsers() will be very quick (won't require another db query).

Code: Select all
class UserTool {
    private $users = null;
    function getUsers(){
        if ( !isset($this->users) ){
            $out = array();
            $res = mysql_query("select * from users");
            while ($row = mysql_fetch_object($res)) $out[] = $row;
            @mysql_free_result($res);
            $this->users = $out;
        }
        return $this->users;
    }
}


That's really all I mean about caching. Just being aware of expensive operations and trying to make it so that expensive operations don't need to be run more than once per request.

-Steve