Miscellaneous ⇒ Chit-Chat ⇒ ACL API ⇒ Community Forums ⇒ CPG Dragonfly™ CMS
Forum IndexChit-Chat

ACL API Reply to topic

Go to page Previous 1, 2, 3 Next

Working on that one, however there are two ways,
Hooks with: Poodle Events or Dragonfly Subject events.

It is floating in my head the idea to use it into DragonflyCMS, so I have some interest on this as well.

As you notice inheritances require adding a "stop rule" for a group to close down permissions.
On my original idea this was called "Reset rule", and its a also valid way to handle ACLs.
But when you have multiple groups accessing the parent resource, you will need to specify multiple "Reset" rules unless a gid=0 (all groups) reset is encountered (always from my original idea.

Another way to inherit permissions is to use bits trickeries.
For example we specify only required bits for a certain resource:
Visitor: AUTH::READ User: AUTH::SAVE | AUTH::APPEND Extended: AUTH::EDIT | AUTH::DELETE

Result would be
Visitor / AUTH::VIEW Visitor /forums AUTH::VIEW User /forums AUTH::VIEW | AUTH::SAVE | AUTH::APPEND Extended /forums/viewforum=8 AUTH::VIEW | AUTH::SAVE | AUTH::APPEND | AUTH::EDIT | AUTH::DELETE
What if we want to deny AUTH::SAVE and AUTH::APPEND to Anyone in forums=8?
Original Rules:
Visitor: AUTH::READ User: AUTH::SAVE | AUTH::APPEND *Extended: AUTH::SAVE | AUTH::APPEND | AUTH::EDIT | AUTH::DELETE

Result would be
Visitor / AUTH::VIEW Visitor /forums AUTH::VIEW User /forums AUTH::VIEW Extended /forums/viewforum=8 AUTH::VIEW | AUTH::SAVE | AUTH::APPEND | AUTH::EDIT | AUTH::DELETE


What the above mean, add additional AUTH and inherit the rest, but if we specify "already" existing AUTH those will be taken off from the parent.

.:: I met php the 03 December 2003 :: Unforgettable day! ::.

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
CloudLinux / Apache 2.4 LSAPI / MySQLi 5.6 / PHP 5.6 / DCVS


my approach was the following :

the * path is the root acl, so in the example we have read rights every where
ID path oid allow deny 1 * * 1 0 2 news admins 255 3 news#cat=2 Anonymous 0 255 4 news#cat=2 GRP_Mod 127 0 5 news#cat=2#title GRP_Mod 0 14

As posted before a deny rule will always be priorized in case of conflict.

a module must make all ACL->evaluate request it needs upon the granularity wished.
In other words the news module having the granularity implemented to allow ACL for specific Categories and further more for the title field of each news will check this each time an access to these elements is done, for reading, writting, etc .... (see next post about more thoughts on this)

acl->evaluate for the path news#cat=2#title will do a boolean & for all rules belonging to the current user.
The result for anonymous would be
ID path oid allow deny 1 * * 1 0 3 news#cat=2 Anonymous 0 255 --------------------------------------------------- res news#cat=2 Anonymous 1 255
so no access. i agree the example is a bit buggous because the access should be denied before having to check if the title can be edited. it's only to show the idea of the heritance algo.

the same as a member of GRP_MOD

ID path oid allow deny 1 * * 1 0 4 news#cat=2 GRP_Mod 127 0 5 news#cat=2#title GRP_Mod 0 14 ------------------------------------------------- res news#cat=2#title GRP_MOD 127 14

this results in 127-14 = 124 (read, execute, custom1, custom2)

Now image the user USR_SU is member of GRP_MOd and also logged with his admin account "admin"
ID path oid allow deny 1 * * 1 0 2 news admins 255 4 news#cat=2 GRP_Mod 127 0 5 news#cat=2#title GRP_Mod 0 14 ------------------------------------------------ res news#cat=2#title USR_SU,admin 255 14
this results in 255-14 = 124 (read, execute, custom1, custom2, acl), BAM!
ACL planning not good or ACL API not powerfull enough.

but as said before, the idea of "reset rules" would be complicated and be a sources more of errors while my approach always will deny access when an error is done.

That said we can imagine a rule saying if an acl for an administrator account conflicts with a group or user acl it will win. If a user acl conflicts with a group acl it the user ACL will win. The logic is simple for the end user.

Here the method evaluate of my current ACL class. remember about my poor programming skills, i'm sure it can be a lot optimized, please be indulgent.

public static function evaluate($path="*", $acl_request=255) { // path strings are representing the path to an element. the path separator is :: // The first element in the path is always the module name and it is up to each module to handle child elements on it's own. // This way one module can handle submodules, datafields, user actions and much more global $userinfo, $CLASS; $t = $path; $result = false; $userid =$userinfo["user_id"]; $adminid = $CLASS['member']->admin_id; $resulting_acl = new AppLib_ACL(array("path"=>"$path", "owner_type"=>self::APPLIB_OWNERTYPE_USER, "owner" => $userid, "allow" => "0", "deny" => "0"), "temp"); // loop through the requested path string and cut of the last element by each loop. // This way the expected granularity is given.We first check the leaf and then walk upwards to the root // At each loop we check if the current user or the groups he is belonging to has a defined ACL // If a matching ACL is found we check it against the requested ACL, if it matches we return true, else we return false. while (strlen($t) > 0 ) { foreach (self::$acl_cache as $acl) { // TODO:acl_cache holds all ACLs loaded upon init, perfectible!! if ( ($acl->path == $t || $acl->path == "*") && // Check user and his groups for existing ACLs ( // user belongs to the group the ACL is defined for, or for all groups (*) ($acl->owner_type == self::APPLIB_OWNERTYPE_GROUP && (in_group($acl->owner) || $acl->owner == "*" )) || // an ACL exists for this user or for all users (*) ($acl->owner_type == self::APPLIB_OWNERTYPE_USER && ($acl->owner == $userid || $acl->owner == "*")) || // an ACL exists for this admin or for all admins (*) ($acl->owner_type == self::APPLIB_OWNERTYPE_ADMIN && ($acl->owner == $adminid || $acl->owner == "*")) ) ) { // Ok, an ACL is found and it belogns to the current user. // check the ACL itself and if it matches the result. // If the ACL is APPLIB_ACL_NONE it will directly return false since // a deny will override grants. $resulting_acl->allow |= $acl->allow; $resulting_acl->deny |= $acl->deny; /*if ($res == $acl_request) { $result = $res; } else { return false; }*/ } } $t = explode("::",$t); end($t); array_pop($t); $t = implode("::", $t); } $delta = $resulting_acl->allow & $resulting_acl->deny; $resulting_acl->allow ^= $delta; if (($resulting_acl->allow & $acl_request) == $acl_request) { //self::$total_ACL_cpu_time += (get_microtime() - $start); return true; } //self::$total_ACL_cpu_time += (get_microtime() - $start); return false; }

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


movix wrote

In other words the news module having the granularity implemented to allow ACL for specific Categories and further more for the title field of each news will check this each time an access to these elements is done, for reading, writting, etc .... (see next post about more thoughts on this)


so here the post to this.

The point on this is that a big part of the ACL process should perhaps be located in the database layer.

The first advantage of that is a better security since we can block unwished access before the database queries are done.

The second is an easier way for developpers to write modules since they do not worry about ACL API calls in there code for pure data access functions since a $db->sql_query would return an error.

The third advantage is that on database layer it would be a lot easier to handle the question of the specific user SELF.
Most modules have a lot of work in handling specific accesses to data if the current user is the creator/owner of the data. An ACL API that can not handle this situation is perhaps not worth to be used.
Imagine the database layer keeps track on the creator of each record in the whole database.

On top of this the ACL API stays of course availlable for specific accesses to the modules, for example functionnalities like moderation of forums. But i guess even this could be handled on database level.

Some will say it starts to become phylosophical, but i'm curious to see your reactions on this.

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


sorry, i juste noticed that there is a lot of comments in the code and i cannot any more edit my post.

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


OMG! It's so uggly to read, i did not closed the 'code' tags correctly in the post above!

please can an admin give me the right to edit my post above?
Mouhahaha Smile

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


Thank you for correcting my mistake.

No more reactions ? i hope i did not offense somebody with my last joke. if so, i appolgize.

I also figured out another advantage in binding an ACL mecanism in the database layer.

Imagine admins can install modules by downloading them from the admin space. The do not need an FTP access to the web space nor they need to know DB credentials.

On this basis we can have modules accessing core data or data from other modules. Having each module admin managing the ACLs for his data the protection is garanteed system wide by the core.

I hope i do not speak about things allready planed for V10. It's true that i did not spent a lot of time looking at V10.

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


After spending a couple of evenings on this topic i made some corrections to the method posted before.

It was a quick shot and i agree with some errors!
So i come up with this cleaner and more tested version.
Everything works like i described in this post.
I also made an jquery based editor for the ACLs.

I will continue on this and post the whole class once finished.
I just had to post this corrected version of the method because of the enourmous errors in the previous one.

public static function evaluate($path="*", $acl_request=255, $sys=false) { // path strings are representing the path to an element. the path separator is :: // The first element in the path is always the module name or a system object and it is up to each of them to handle child elements on their own. // This way one can handle submodules, datafields, user actions and much more global $userinfo, $CLASS; $t = $path; $userid =$userinfo["user_id"]; $adminid = $CLASS['member']->admin_id; $resulting_acl = new applib_acl(array("path"=>"$path", "owner_type"=>self::APPLIB_OWNERTYPE_USER, "owner" => $userid, "allow" => "0", "deny" => "0"), "temp"); // loop through the requested path string and cut of the last element by each loop. // This way the expected granularity is given. We first check the leaf and then walk upwards to the root // At each loop we check if the current user or the groups he is belonging to has a defined ACL while (strlen($t) > 0 ) { foreach (self::$acl_cache as $acl) { // DOIT:acl_cache holds all ACLs loaded upon init, perfectible!! if ( ($acl->path == $t || $acl->path == "*") && // Check user and his groups for existing ACLs ( // Global wildcarded ACLS ($acl->owner_type == self::APPLIB_OWNERTYPE_ALL) || // System ACLs ($acl->owner_type == self::APPLIB_OWNERTYPE_SYSTEM && $sys) || // user belongs to the group the ACL is defined for, or for all groups (*) ($acl->owner_type == self::APPLIB_OWNERTYPE_GROUP && (in_group($acl->owner) || (is_user() && $acl->owner == "*" ))) || // an ACL exists for this user or for all users (*) ($acl->owner_type == self::APPLIB_OWNERTYPE_USER && ($acl->owner == $userid || (is_user() && $acl->owner == "*"))) || // an ACL exists for this admin or for all admins (*) ($acl->owner_type == self::APPLIB_OWNERTYPE_ADMIN && ($acl->owner == $adminid || (is_admin() && $acl->owner == "*"))) ) ) { // Sum allow and deny into the resulting ACL $resulting_acl->allow |= $acl->allow; $resulting_acl->deny |= $acl->deny; } } $t = explode("::",$t); end($t); array_pop($t); $t = implode("::", $t); } // a deny will override grants. $delta = 255 ^ $resulting_acl->deny; $resulting_acl->allow = $resulting_acl->allow & $delta; // compare to requested ACL, if match return true if (($resulting_acl->allow & $acl_request) == $acl_request) { return true; } return false; }

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


I'm sure you do not reply because there is still en error in my method.

after some further testing here the line of the method that computes the resulting ACL

$resulting_acl->allow = ((255 ^ $resulting_acl->allow) | $resulting_acl->deny) ^ 255;

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


the fact havin admin separated from regular users complicates the situation.
As a user can be logged in as an admin and simultanously as a regular user creates more conflict situation then we would have if there is only one authentification.

To resolve this conflict situation i adopt one rule suggested earlier in this thread. Admin rights will always overwrite regular user rights.

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


movix wrote
I'm sure you do not reply because there is still en error in my method.



After some troubleshooting I found an error in the footer of your website they may be the cause of the no-reply bug your experiencing. Screenshot Provided to show error.

We apologize for the inconvenience, I suspect by fixing the error in your footer that should resolve the no-reply bug.

Thank you for choosing Dragonfly! Have a wonderful day.
Attachment: fireshot_screen_capture.png
Description Credits Removed
Filename fireshot_screen_capture.png
Filesize 3.88 KiB
Downloaded 9 Time(s)
You are not allowed to view/download this attachment

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Multiple Setups


ah!
Sorry about that, but i asked a while ago in this topic
dragonflycms.org/Forum...24322.html
about having credits and other legal stuff conentrated on one dedicatetd page.

So doing this way is not ok ?

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


Members are requested to retain the full copyright as shown in the footer of every page "Interactive software released under GNU GPL 2, Code Credits". If for good reason this message cannot be displayed we request at least the "credits" link be retained ... said message should be plainly visible and not hidden in the background color, etc..
Members who remove (or fail to display on their own template) this message will receive no support here. Users found adding copyrights back for a short period and then removing them after obtaining support will find that future aid will not be given. Members who remove credits will be issued a "credit violators rank - (IMAGE), to alert all members of the violation. Rank removed when credits returned.


dragonflycms.org/Wiki/id=58.html
Section 4 sub-section j and k

Instead of the full "Interactive software released under GNU GPL 2, Code Credits" in the footer you can have just a link going to the www.i-motion.fr/index....me=credits page.

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Multiple Setups


ok, i'll fix it asap and sorry for this.

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


done

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0


hi,

here is what i have done so far.
I packaged it as a module.

The module is made of a PHP class al_acl and some JS code. I know that jquery is not used in the DF core but as my best JS skills are with jquery this module is using it.

In order to define new ACL you can simply add records to the ACL table with your own code.
The al_acl class holds a constant defining the path separator string that should be used to avoid mistakes.


To allow editing of acls you can add a button in your UI for each acl. The button should call the following JS function to allow editing of a specific acl
acl_dialog.acl_query_server(acl_path);
"acl_path" holds the ACL path you want to edit. If no record is defined for this ACL in the database it will of course be added.

The ACL editor will show all ACLs applied to the requested path, inherited ones and those specifically applied to the path. You cannot change ACL values for inherited ACLs. But adding some ACL values currently not defined on inherited ACLS will created a new one for the specific path.

Currently for testing if calling the module index.php you will get a list of all acl defined in the database.

To check if the current user has access to an object use the method al_acl::evaluate() as described below.

al_acl::evaluate($path, $acl, $check_owner, $sys); $path : is the path you defined some acls for or not $acl : is the acl you want to check, it is always done against the current user upon his regular user, a group membership, an admin account he is loggin in with or the ownership of the requested path. $check_owner : this flag allows to prevent the cheking of the ownership since it currently represents a lot of SQL queries. $sys: currently not used

As the class al_acl is loading the required JS libraries upon loading the class you should do so befor calling the header.php include.
If using some autoloader also be aware that you must do your first call to an al_acl property or method before header.php

If using blocks that uses this you should load the class in a header.php or cmsinit.inc

Concerning object ownership : A dedicated table is created by this module where you define the ownerships of objects. this solution is not the best. As stated before i think this part should be located in the database layer that would create the onwership records upon INSERT statements.

Please note that this is a first throw and of course perfectible at many place. Currently if debuging is activated you'll get some output for each call af the eavluate method.
For what i tested so far it works fine and quite fast. I did no stress test to see how if work on heavy load.

Finaly, as this thread is still in chit-chat please let me know if the topic is of no intereset or if the license problem you identified pushes me out of every exchange on these forums.
Attachment: applib_acl.zip
Description Module AppLib_ACL
Filename applib_acl.zip
Filesize 163.87 KiB
Downloaded 1 Time(s)
You are not allowed to view/download this attachment

Server specs (Server OS / Apache / MySQL / PHP / DragonflyCMS):
Linux/Apache/MySQL 5.1.49/PHP 5.3.6/ DF 9.3.2.0

All times are UTC
Go to page Previous 1, 2, 3 Next


Jump to: