Re: Best way to accomplish acl for database records owned by a user
Thanks again for additional pointers. I got many interesting information how to create a row level based access. We are going to make some tests to see which is the best solution in our case. rOger On Sep 25, 10:23 pm, brian wrote: > On Fri, Sep 25, 2009 at 2:25 AM, rOger wrote: > > > Thanks for your answers!! > > > @brian: It looks rather complex to accomplish such a "easy" task so I > > think there must be an easier way to get the same result... > > Yeah, sure it's complex. As I pointed out, though, the example I > posted goes a little further than what you're looking for. But I > wanted to post it in full so you'd see the context. The nutshell > version is to query the ACO table using inner joins on both aros & > aros_acos. The record ID you're checking access to corresponds to > Aro.foreign_key. > > I have no idea if this is THE way to do it, as I couldn't find > anything much about record-level ACL and Cake. This is what I figured > out on my own and it seems to work great (at least, for my app). --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "CakePHP" group. To post to this group, send email to cake-php@googlegroups.com To unsubscribe from this group, send email to cake-php+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/cake-php?hl=en -~--~~~~--~~--~--~---
Re: Best way to accomplish acl for database records owned by a user
On Fri, Sep 25, 2009 at 2:25 AM, rOger wrote: > > Thanks for your answers!! > > @brian: It looks rather complex to accomplish such a "easy" task so I > think there must be an easier way to get the same result... Yeah, sure it's complex. As I pointed out, though, the example I posted goes a little further than what you're looking for. But I wanted to post it in full so you'd see the context. The nutshell version is to query the ACO table using inner joins on both aros & aros_acos. The record ID you're checking access to corresponds to Aro.foreign_key. I have no idea if this is THE way to do it, as I couldn't find anything much about record-level ACL and Cake. This is what I figured out on my own and it seems to work great (at least, for my app). --~--~-~--~~~---~--~~ You received this message because you are subscribed to the Google Groups "CakePHP" group. To post to this group, send email to cake-php@googlegroups.com To unsubscribe from this group, send email to cake-php+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/cake-php?hl=en -~--~~~~--~~--~--~---
Re: Best way to accomplish acl for database records owned by a user
I came across this same issue. You can call it "row level access". An article that pointed me in the right direction was this one: http://teknoid.wordpress.com/2009/04/22/simplistic-example-of-row-level-access-control-with-auth-security-and-app-model-in-cakephp/. I took that article and expanded on it. The key for my application was the design of the database. My application has distributors that own dealers that then have service advisers. A distributor should be able to access only his distributor record and the associated dealers and the associated service advisers. A dealer can access only his dealer record and his service advisers. Etc., etc. Distributors and dealers and service advisers are individual group records. There are users belonging to those groups. Currently I don't allow a user to be in multiple groups, but I could. So using the article above I was able to build in internal security using the group_id as a first cut for access to the record being requested, and then the user_id as well to make sure it was "their" record. For the security on associated records this is where having the 'belongsTo' and 'hasMany' relationships really helped. But the real key discovery for me was in my dealers_controller.php. I needed to reach back and get the associated distributor for the dealer record being requested to compare if it was the same distributor. If not, no access. I found I could use var $uses = array('Dealers' 'Distributors') to allow me to bring in the distributor (only one field actually, the 'id') to my security check. It is some code. I'm sure it could be cleaned up a bit and maybe put more into the model to have a skinnier controller, but it is working well and seems to be a flexible approach that does not involve the complexities of ACL. Maybe some of this helps. On Sep 25, 1:25 am, rOger wrote: > Thanks for your answers!! > > @brian: It looks rather complex to accomplish such a "easy" task so I > think there must be an easier way to get the same result... > > @Rick: Your solution is the one I used before but I thought that there > must be a solution that is integrated into the ACO/ACL concept... > > It's always the same problem with every framework; simple tasks are > easy; real world scenarios are big challenges. It would be interesting > to know how the developers of cakePHP/ACL-system would accomplish this > task... > > regards, > rOger > > On 24 Sep., 16:09, Rick wrote: > > > I know that globals are bad but... > > > I just set a global $gblCurrentUser when the user logs in. Then > > accessing that in models, I can add a select condition for that user > > in the beforeFind etc.. > > > You get the idea? > > > Rick > > > On Sep 24, 12:20 am, brian wrote: > > > > I did something similar to this. However, I was so overwhelmed by the > > > contradictory and/or incomplete information I found about Cake's ACL > > > (mostly because it was quite dated) that I really don't know for sure > > > that I did it the best way. > > > > My app is an extranet that has several different Groups. The > > > navigation consists of many Sections that are stored as a tree (MPTT). > > > Some Sections may not be seen by certain Groups. So, to display this > > > navigation tree, I called this method in my SectionsController: > > > > public function nav($group_id = null) > > > { > > > if (is_null($group_id)) > > > { > > > if (!$this->params['admin']) > > > { > > > $group_id = $this->Auth->user('group_id'); > > > } > > > } > > > $this->Session->write('group_id_for_nav', $group_id); > > > > /* try getting the nodes from the cache > > > */ > > > $sections = Cache::read("group_sections_${group_id}", 'default'); > > > > if (!$sections) > > > { > > > /* fetch the permissions for this group > > > */ > > > $perms = $this->Acl->Aco->find( > > > 'all', > > > array( > > > 'fields' => array('Aco.foreign_key'), > > > 'conditions' => array( > > > 'Aco.model' => 'Section', > > > 'Aco.id = Permission.aco_id' > > > ), > > > 'recursive' => -1, > > > 'joins' => array( > > > array( > > > 'table' => 'aros', > > > 'alias' => 'Aro', > > > 'type' => 'INNER', > > > 'conditions'=> array( > > > 'Aro.model' => > > > 'Group', > > >
Re: Best way to accomplish acl for database records owned by a user
Thanks for your answers!! @brian: It looks rather complex to accomplish such a "easy" task so I think there must be an easier way to get the same result... @Rick: Your solution is the one I used before but I thought that there must be a solution that is integrated into the ACO/ACL concept... It's always the same problem with every framework; simple tasks are easy; real world scenarios are big challenges. It would be interesting to know how the developers of cakePHP/ACL-system would accomplish this task... regards, rOger On 24 Sep., 16:09, Rick wrote: > I know that globals are bad but... > > I just set a global $gblCurrentUser when the user logs in. Then > accessing that in models, I can add a select condition for that user > in the beforeFind etc.. > > You get the idea? > > Rick > > On Sep 24, 12:20 am, brian wrote: > > > I did something similar to this. However, I was so overwhelmed by the > > contradictory and/or incomplete information I found about Cake's ACL > > (mostly because it was quite dated) that I really don't know for sure > > that I did it the best way. > > > My app is an extranet that has several different Groups. The > > navigation consists of many Sections that are stored as a tree (MPTT). > > Some Sections may not be seen by certain Groups. So, to display this > > navigation tree, I called this method in my SectionsController: > > > public function nav($group_id = null) > > { > > if (is_null($group_id)) > > { > > if (!$this->params['admin']) > > { > > $group_id = $this->Auth->user('group_id'); > > } > > } > > $this->Session->write('group_id_for_nav', $group_id); > > > /* try getting the nodes from the cache > > */ > > $sections = Cache::read("group_sections_${group_id}", 'default'); > > > if (!$sections) > > { > > /* fetch the permissions for this group > > */ > > $perms = $this->Acl->Aco->find( > > 'all', > > array( > > 'fields' => array('Aco.foreign_key'), > > 'conditions' => array( > > 'Aco.model' => 'Section', > > 'Aco.id = Permission.aco_id' > > ), > > 'recursive' => -1, > > 'joins' => array( > > array( > > 'table' => 'aros', > > 'alias' => 'Aro', > > 'type' => 'INNER', > > 'conditions'=> array( > > 'Aro.model' => > > 'Group', > > "Aro.foreign_key = > > ${group_id}" > > ) > > ), > > array( > > 'table' => 'aros_acos', > > 'alias' => 'Permission', > > 'type' => 'INNER', > > 'conditions'=> array( > > 'Permission.aro_id > > = Aro.id', > > 'Permission._read > > >= 0' > > ) > > ) > > ) > > ) > > ); > > > $section_ids = Set::extract($perms, '{n}.Aco.foreign_key'); > > > /* we don't want to see the root node > > */ > > unset($section_ids[0]); > > > /* now grab the sections these permissions allow > > */ > > $sections = $this->Section->threaded($section_ids); > > > /* save this group's allowed sections > > */ > > Cache::write("group_sections_${group_id}", $sections, > > 'default'); > > } > > return $sections; > > > } > > > So, the Aco.foreign_key fields I'm after correspond to Section.ids. > > Once i have those, I fetch the relevant Sections as a threaded list. > > Obviously, you'd just be interested in the record IDs. > > > What I'm storing in the cache is the Sections themselves. For your > > case, you'd likely want to save the record IDs in the session instead > > of caching them. > > > Anyway, the important thing is the joins used to get at the model IDs > > for your reco
Re: Best way to accomplish acl for database records owned by a user
You could also just use $this->Auth->user('id') which gets the info from the session. On Thu, Sep 24, 2009 at 10:09 AM, Rick wrote: > > I know that globals are bad but... > > I just set a global $gblCurrentUser when the user logs in. Then > accessing that in models, I can add a select condition for that user > in the beforeFind etc.. > > You get the idea? > > Rick > > > > > On Sep 24, 12:20 am, brian wrote: >> I did something similar to this. However, I was so overwhelmed by the >> contradictory and/or incomplete information I found about Cake's ACL >> (mostly because it was quite dated) that I really don't know for sure >> that I did it the best way. >> >> My app is an extranet that has several different Groups. The >> navigation consists of many Sections that are stored as a tree (MPTT). >> Some Sections may not be seen by certain Groups. So, to display this >> navigation tree, I called this method in my SectionsController: >> >> public function nav($group_id = null) >> { >> if (is_null($group_id)) >> { >> if (!$this->params['admin']) >> { >> $group_id = $this->Auth->user('group_id'); >> } >> } >> $this->Session->write('group_id_for_nav', $group_id); >> >> /* try getting the nodes from the cache >> */ >> $sections = Cache::read("group_sections_${group_id}", 'default'); >> >> if (!$sections) >> { >> /* fetch the permissions for this group >> */ >> $perms = $this->Acl->Aco->find( >> 'all', >> array( >> 'fields' => array('Aco.foreign_key'), >> 'conditions' => array( >> 'Aco.model' => 'Section', >> 'Aco.id = Permission.aco_id' >> ), >> 'recursive' => -1, >> 'joins' => array( >> array( >> 'table' => 'aros', >> 'alias' => 'Aro', >> 'type' => 'INNER', >> 'conditions'=> array( >> 'Aro.model' => >> 'Group', >> "Aro.foreign_key = >> ${group_id}" >> ) >> ), >> array( >> 'table' => 'aros_acos', >> 'alias' => 'Permission', >> 'type' => 'INNER', >> 'conditions'=> array( >> 'Permission.aro_id = >> Aro.id', >> 'Permission._read >= >> 0' >> ) >> ) >> ) >> ) >> ); >> >> $section_ids = Set::extract($perms, '{n}.Aco.foreign_key'); >> >> /* we don't want to see the root node >> */ >> unset($section_ids[0]); >> >> /* now grab the sections these permissions allow >> */ >> $sections = $this->Section->threaded($section_ids); >> >> /* save this group's allowed sections >> */ >> Cache::write("group_sections_${group_id}", $sections, >> 'default'); >> } >> return $sections; >> >> } >> >> So, the Aco.foreign_key fields I'm after correspond to Section.ids. >> Once i have those, I fetch the relevant Sections as a threaded list. >> Obviously, you'd just be interested in the record IDs. >> >> What I'm storing in the cache is the Sections themselves. For your >> case, you'd likely want to save the record IDs in the session instead >> of caching them. >> >> Anyway, the important thing is the joins used to get at the model IDs >> for your record-level ACL through the ACO.foreign_key. >> >> Let me know if you want more info. >> >> On Wed, Sep 23, 2009 at 5:19 PM, rOger wrote: >> >> > Hi @all, >> >> > I'm really new to CakePHP and I read about the ACL modell of CakePHP. >> > As usual also the examples seems to be simple so it is easy to >> > understand the system. I'm evaluating cakePHP for a new project where >> > I have records which belongs to a given user = that is the owner of >> > the record. Now I want to have a ACL system which enables some groups >> > (like
Re: Best way to accomplish acl for database records owned by a user
I know that globals are bad but... I just set a global $gblCurrentUser when the user logs in. Then accessing that in models, I can add a select condition for that user in the beforeFind etc.. You get the idea? Rick On Sep 24, 12:20 am, brian wrote: > I did something similar to this. However, I was so overwhelmed by the > contradictory and/or incomplete information I found about Cake's ACL > (mostly because it was quite dated) that I really don't know for sure > that I did it the best way. > > My app is an extranet that has several different Groups. The > navigation consists of many Sections that are stored as a tree (MPTT). > Some Sections may not be seen by certain Groups. So, to display this > navigation tree, I called this method in my SectionsController: > > public function nav($group_id = null) > { > if (is_null($group_id)) > { > if (!$this->params['admin']) > { > $group_id = $this->Auth->user('group_id'); > } > } > $this->Session->write('group_id_for_nav', $group_id); > > /* try getting the nodes from the cache > */ > $sections = Cache::read("group_sections_${group_id}", 'default'); > > if (!$sections) > { > /* fetch the permissions for this group > */ > $perms = $this->Acl->Aco->find( > 'all', > array( > 'fields' => array('Aco.foreign_key'), > 'conditions' => array( > 'Aco.model' => 'Section', > 'Aco.id = Permission.aco_id' > ), > 'recursive' => -1, > 'joins' => array( > array( > 'table' => 'aros', > 'alias' => 'Aro', > 'type' => 'INNER', > 'conditions'=> array( > 'Aro.model' => > 'Group', > "Aro.foreign_key = > ${group_id}" > ) > ), > array( > 'table' => 'aros_acos', > 'alias' => 'Permission', > 'type' => 'INNER', > 'conditions'=> array( > 'Permission.aro_id = > Aro.id', > 'Permission._read >= > 0' > ) > ) > ) > ) > ); > > $section_ids = Set::extract($perms, '{n}.Aco.foreign_key'); > > /* we don't want to see the root node > */ > unset($section_ids[0]); > > /* now grab the sections these permissions allow > */ > $sections = $this->Section->threaded($section_ids); > > /* save this group's allowed sections > */ > Cache::write("group_sections_${group_id}", $sections, > 'default'); > } > return $sections; > > } > > So, the Aco.foreign_key fields I'm after correspond to Section.ids. > Once i have those, I fetch the relevant Sections as a threaded list. > Obviously, you'd just be interested in the record IDs. > > What I'm storing in the cache is the Sections themselves. For your > case, you'd likely want to save the record IDs in the session instead > of caching them. > > Anyway, the important thing is the joins used to get at the model IDs > for your record-level ACL through the ACO.foreign_key. > > Let me know if you want more info. > > On Wed, Sep 23, 2009 at 5:19 PM, rOger wrote: > > > Hi @all, > > > I'm really new to CakePHP and I read about the ACL modell of CakePHP. > > As usual also the examples seems to be simple so it is easy to > > understand the system. I'm evaluating cakePHP for a new project where > > I have records which belongs to a given user = that is the owner of > > the record. Now I want to have a ACL system which enables some groups > > (like Administrators) full access to these records. That is the "easy" > > part and is well documented. The second part is a little bit more > > tricky (in my opinion): The owner should also have full access to his > > record detai
Re: Best way to accomplish acl for database records owned by a user
I did something similar to this. However, I was so overwhelmed by the contradictory and/or incomplete information I found about Cake's ACL (mostly because it was quite dated) that I really don't know for sure that I did it the best way. My app is an extranet that has several different Groups. The navigation consists of many Sections that are stored as a tree (MPTT). Some Sections may not be seen by certain Groups. So, to display this navigation tree, I called this method in my SectionsController: public function nav($group_id = null) { if (is_null($group_id)) { if (!$this->params['admin']) { $group_id = $this->Auth->user('group_id'); } } $this->Session->write('group_id_for_nav', $group_id); /* try getting the nodes from the cache */ $sections = Cache::read("group_sections_${group_id}", 'default'); if (!$sections) { /* fetch the permissions for this group */ $perms = $this->Acl->Aco->find( 'all', array( 'fields' => array('Aco.foreign_key'), 'conditions' => array( 'Aco.model' => 'Section', 'Aco.id = Permission.aco_id' ), 'recursive' => -1, 'joins' => array( array( 'table' => 'aros', 'alias' => 'Aro', 'type' => 'INNER', 'conditions'=> array( 'Aro.model' => 'Group', "Aro.foreign_key = ${group_id}" ) ), array( 'table' => 'aros_acos', 'alias' => 'Permission', 'type' => 'INNER', 'conditions'=> array( 'Permission.aro_id = Aro.id', 'Permission._read >= 0' ) ) ) ) ); $section_ids = Set::extract($perms, '{n}.Aco.foreign_key'); /* we don't want to see the root node */ unset($section_ids[0]); /* now grab the sections these permissions allow */ $sections = $this->Section->threaded($section_ids); /* save this group's allowed sections */ Cache::write("group_sections_${group_id}", $sections, 'default'); } return $sections; } So, the Aco.foreign_key fields I'm after correspond to Section.ids. Once i have those, I fetch the relevant Sections as a threaded list. Obviously, you'd just be interested in the record IDs. What I'm storing in the cache is the Sections themselves. For your case, you'd likely want to save the record IDs in the session instead of caching them. Anyway, the important thing is the joins used to get at the model IDs for your record-level ACL through the ACO.foreign_key. Let me know if you want more info. On Wed, Sep 23, 2009 at 5:19 PM, rOger wrote: > > Hi @all, > > I'm really new to CakePHP and I read about the ACL modell of CakePHP. > As usual also the examples seems to be simple so it is easy to > understand the system. I'm evaluating cakePHP for a new project where > I have records which belongs to a given user = that is the owner of > the record. Now I want to have a ACL system which enables some groups > (like Administrators) full access to these records. That is the "easy" > part and is well documented. The second part is a little bit more > tricky (in my opinion): The owner should also have full access to his > record details (means should be editable) but other users should have > no access. That means that the ACL system has to decide according to a > field value of a record if the user has access to or not. > > I hope it is clear what I need and hope that someone can spend some > light on this issue. > > Thanks in advance, > rOger > > > > --~--~-~--~~~---~--~~ Yo