Thanks for posting all this. I've just started--yesterday--trying to work out how to go about something similar. I haven't used ACL at all and I was really confused about row-level access. It looks like I'll be able to adapt your code for my use. The one big difference is that I'll need to control a model that implements TreeBehavior (think folder hierarchy).
One thing I'd change is in su_index(): put the check on group_id at the top to avoid all that logic. function su_index() { $conditions = null; if ($this->Auth->user('group_id') == 4) { $papers = array(); $user_id = $this->Auth->user('id'); $nodes = $this->Acl->Aro->findByForeignKeyAndModel($user_id, 'User'); foreach ($nodes['Aco'] as $node) { if ($node['model'] === 'Paper') { $papers[] = $node['foreign_key']; } // Get children from volumes if ($node['model'] === 'Volume') { $children = $this->Acl->Aco->children($node['id']); foreach ($children as $child) { $papers[] = $child['Aco']['foreign_key']; } } } $conditions = array('Paper.id' => $papers); } $this->set('papers', $this->paginate($conditions)); } Although, if it were my project, I'd make the admin group ID 1. If you later add more groups you'll run into problems. Having said _that_, though, I have to say that I'm a bit confused about how this is supposed to work. If it's an admin, you want all files to show up, otherwise, check ACL for access. You're getting the $user_id from the session, but it appears that this is an admin-only method. (Is 'su' your admin prefix?) If you want that an admin can see the allowed Papers for a particular user, I'd think you'd need to pass the ID as a param. Did I read that correctly? On Sun, Mar 1, 2009 at 1:43 PM, Aidan Lister <aidanlis...@gmail.com> wrote: > > The final piece of the puzzle. > > The only thing remaining was displaying the list of papers and volumes > that a user had access to, instead of all the papers/volumes. > > <?php > // papers_controller.php > function su_index() > { > $papers = array(); > $user_id = $this->Auth->user('id'); > $nodes = $this->Acl->Aro->findByForeignKeyAndModel($user_id, > 'User'); > foreach ($nodes['Aco'] as $node) { > if ($node['model'] === 'Paper') { > $papers[] = $node['foreign_key']; > } > > // Get children from volumes > if ($node['model'] === 'Volume') { > $children = $this->Acl->Aco->children($node['id']); > foreach ($children as $child) { > $papers[] = $child['Aco']['foreign_key']; > } > } > } > $conditions = array('Paper.id' => $papers); > > if ($this->Auth->user('group_id') == 4) { > $conditions = null; > } > > $this->set('papers', $this->paginate($conditions)); > } > ?> > > The same applies to the volumes controller, but a little simpler as > you don't need the hierarchy. > > There must be an easier way to retrieve a set of Model records given > an ARO and a parent ACO, but I couldn't find it. > > If anyone has any tips/suggestions, let me know. > > HTH, > Aidan > > > On Mar 2, 12:13 am, Aidan Lister <aidanlis...@gmail.com> wrote: >> For the archives, this is a step-by-step on how I solved the problem: >> >> Rather than controllers/Papers/view/n which becomes unwieldy given you >> have to create an ACO for each action, I instead created an ACO for >> each row in my two models. Thanks to markstory for the suggestion. >> >> I created the following ACO heirachy: >> Papers/<volume id>/<paper id> >> >> This allowed me to give editors access to a volume, which >> automatically gives access to the papers inside. This is the beauty of >> ACLs. >> >> I created the ACO tree like so (using acltool, a custom cake shell >> component): >> >> <?php >> // $ cake acltool aco_models >> function aco_models() >> { >> $this->out('Starting models sync'); >> $Paper = ClassRegistry::init('Paper'); >> $Volume = ClassRegistry::init('Volume'); >> >> // Create the root node >> $root_alias = 'papers'; >> $this->Aco->create(); >> $this->Aco->save(array('parent_id' => null, 'model' => null, >> 'alias' => $root_alias)); >> $aco_root = $this->Aco->id; >> >> // Iterate all the volumes >> $volumes = $Volume->findAll(); >> foreach ($volumes as $volume) { >> // Create a node for the volume >> $this->out(sprintf('Created Aco node: %s/%s', $root_alias, >> $volume['Volume']['number'])); >> $this->Aco->create(); >> $row = array('parent_id' => $aco_root, 'foreign_key' => >> $volume['Volume']['id'], 'model' => 'Volume', 'alias' => $volume >> ['Volume']['number']); >> $this->Aco->save($row); >> $parent_id = $this->Aco->id; >> >> // Iterate all the papers >> $papers = $Paper->find('all', array('conditions' => array >> ('volume_id' => $volume['Volume']['id']), 'recursive' => -1)); >> foreach ($papers as $paper) { >> // Create a node for the paper >> $this->out(sprintf('Created Aco node: %s/%s/%s', >> $root_alias, $volume['Volume']['number'], $paper['Paper']['slug'])); >> $this->Acl->Aco->create(); >> $row = array('parent_id' => $parent_id, 'foreign_key' >> => $paper['Paper']['id'], 'model' => 'Paper', 'alias' => $paper >> ['Paper']['slug']); >> $this->Acl->Aco->save($row); >> } >> } >> } >> ?> >> >> Once all the ACOs are created, I gave access to my editors and authors >> like so: >> >> <?php >> // $ cake acltool vol_perms >> function vol_perms() >> { >> // Row level access for volumes >> $this->out('Creating row-level permissions for volumes'); >> $Volume = ClassRegistry::init('Volume'); >> $volumes = $Volume->findAll(); >> foreach ($volumes as $vol) { >> $this->out(sprintf('- Entering volume number %s', $vol >> ['Volume']['number'])); >> $Volume->id = $vol['Volume']['id']; >> foreach ($vol['User'] as $user) { >> $this->out(sprintf('-- Granting access to %s', $user >> ['name'])); >> $User->id = $user['id']; >> $this->Acl->allow($User, $Volume); >> } >> }} >> >> ?> >> >> Next we need to inform our models about our chosen ACO structure: >> >> <?php >> // volume.php >> function parentNode() >> { >> return null; >> } >> >> // paper.php >> function parentNode() >> { >> if (!$this->id && empty($this->data)) { >> return null; >> } >> $data = $this->data; >> if (empty($this->data)) { >> $data = $this->read(); >> } >> if (empty($data['Paper']['volume_id'])) { >> return null; >> } else { >> return array('Volume' => array('id' => $data['Paper'] >> ['volume_id'])); >> } >> } >> ?> >> >> Next, in our controllers that we wish to handle the row-level access >> we do the following: >> >> In beforeFilter, we check that they're not an admin, then we apply our >> Acl check. This relies on the fact that a) access is blocked to users >> by the 'controllers' Aco tree and b) access is granted to editors/ >> volumes to this controller by the 'controllers' Aco tree. Both of >> these constraints are enforced by Auth (with $this->Auth->authorize = >> 'actions'). >> >> <?php >> // Check row-level access >> if (isset($this->params['pass'][0]) && $this->Auth->user >> ('group_id') < 4) { >> $aco = $this->Acl->Aco->findByModelAndForeignKey('Paper', >> $this->params['pass'][0]); >> $aro = $this->Acl->Aro->findByModelAndForeignKey('User', >> $this->Auth->user('id')); >> if (!$this->Acl->check($aro['Aro'], $aco['Aco'])) { >> $this->Session->setFlash($this->Auth->authError); >> $this->redirect(array('su' => true, 'controller' => >> 'papers', 'action' => 'index')); >> } >> } >> ?> >> >> And that's it. If anyone has any improvements or suggestions I'd love >> to here them. >> >> Cheers, >> Aidan Lister >> >> On Mar 1, 4:36 pm, Aidan Lister <aidanlis...@gmail.com> wrote: >> >> > Hello, >> >> > I need to do some additional row level ACL access control for two of >> > my models. >> >> > My system has the following groups: admins, editors, authors and >> > users. >> >> > I'm restricting access to my controller actions using the Auth >> > component, via $this->Auth->authorize = 'actions'. >> >> > At the moment, my authors have access to "controllers/Papers/view", I >> > need to be able to limit their access to "controllers/Papers/view/n". >> > Whether I use a custom query to check access to "n" or an ACL, I don't >> > mind, both are feasible so whichever is easier. >> >> > Similarly, I need to control access to "controllers/Volumes/view/n" >> > for editors. >> >> > Does anyone have any suggestions for achieving this? >> >> > Thanks, >> > Aidan > > > --~--~---------~--~----~------------~-------~--~----~ 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 -~----------~----~----~----~------~----~------~--~---