Namespacing ACL resources and Galahad_Acl

Chris Mor­rell writes; In most of my appli­ca­tions I like to han­dle autho­riza­tion (query­ing the ACL) in one (or more) of three ways:

  • Autho­rize access to a model’s method
  • Autho­rize access to a con­troller action
  • Autho­rize access to an arbi­trary “permission”

In gen­eral I find it’s best to keep autho­riza­tion within the domain (query­ing the ACL within my mod­els when they’re accessed) as this pro­vides the most con­sis­tent behav­ior. For exam­ple, if I even­tu­ally add a REST API to my appli­ca­tion I don’t have to dupli­cate all my autho­riza­tion logic in the new REST con­trollers. When the appli­ca­tion calls some­thing like Default_Model_Post::save() it either saves or throws an ACL excep­tion, no mat­ter where it was called from. This is great in that it saves me from hav­ing to dupli­cate code and keeps my sys­tem more secure.

On the other hand, there are times when it’s just a lot eas­ier to han­dle autho­riza­tion in the con­troller. For exam­ple, if guests should never access my “Admin” mod­ule, it doesn’t make sense to ever let them access /admin/ URLs. Also, if you’re using Zend_Navigation, hav­ing ACL resources that match con­troller actions lets you uti­lize its ACL integration.

If you’re ever going to mix these two tech­niques, you’ll even­tu­ally bump into the case where a model and a con­troller share the same name. What if you need to set per­mis­sions on a “user” con­troller and dif­fer­ent per­mis­sions on a “user” model? This is where name­spacing comes into play. As sug­gested by the Zend Frame­work man­ual, I always name my con­troller action resources in the for­mat mvc:module.controller.action. I name my model resources sim­i­larly, in the for­mat model:module.modelName.methodName. In both the­ses cases, “mvc” and “model” are the name­space, and every­thing fol­low­ing the colon is the actual resource name. Now I can refer to my “admin” mod­ule as mvc:admin and the mod­els within my admin mod­ule as model:admin.

This is where things get interesting.

Read on; “Name­spacing ACL resources & Galahad_Acl”.

Chris con­tin­ues; Right now I treat my mod­els as resources with a spe­cial excep­tion for the user model which is both a resource and a role. Then I actu­ally make the mod­els respon­si­ble for man­ag­ing their own ACL per­mis­sions, both set­ting them up and query­ing them. To facil­i­tate that, I have a base model class that does a few things. First it has a way to inject an ACL instance into the model as well as a way to pass an ACL instance as the default ACL for all mod­els (which I do in my boot­strap). Sec­ond it auto­mat­i­cally adds itself to that ACL (with the resource id model:moduleName.modelName). Finally, I have an _initAcl() method which is called when my model is instan­ti­ated which adds the appro­pri­ate rules to the ACL if they don’t already exist. When­ever my model is doing some­thing that is access-controlled I check the ACL right then.

Here’s a sim­ple code example:


class Default_Model_Post extends Galahad_Model_Entity
{
protected function _initAcl($acl)
{
// Deny permissions to anything on this model unless explicitly allowed
$acl->deny(null, $this);

// Allow guests to fetch the con­tent of posts
$acl->allow(‘guest’, $this, ‘fetch’);

// Allow admins to save changes to posts
$acl->allow(‘admin’, $this, ‘save’);
}

pub­lic func­tion save()
{
if (!$this->getAcl()->isAllowed($this->getRole(), $this, ‘save’)) {
throw new Galahad_Acl_Exception(‘Current user is not allowed to save posts.’);
}

$dataMap­per = $this->getDataMapper();
return $dataMapper->save($this);
}
}

There’s a lit­tle bit more hap­pen­ing in there (for exam­ple, I also have helper meth­ods like get­Role(), which either gets the role ID stored in the model or grabs it from Zend_Auth if avail­able), but you should get the picture.

That way my access con­trol is hap­pen­ing when the access itself is hap­pen­ing. No mat­ter how my model is used, the ACL is always queried right when it mat­ters. I also like set­ting up the ACL this way because all rules are loaded into the the ACL only when they could poten­tially apply (you never need the rules for a Post model if the cur­rent request never even loads the Post class).

This is some­thing I’ve been think­ing about a lot lately, and I’m just set­tling into this method. I just blogged about it a lit­tle over a week ago: “Name­spacing ACL resources & Galahad_Acl” — if any­one has any com­ments I’d love to hear them

Tags: , ,

Leave a Comment

*

Get Adobe Flash playerPlugin by wpburn.com wordpress themes