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 <[email protected]> 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 <[email protected]> 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 [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/cake-php?hl=en
-~----------~----~----~----~------~----~------~--~---