Get it All

I’ve been bouncing my head roughly against the wall and trying to figure out a number of critical points about the way that CakePHP handles ACLs and permissions, authentication and authorization. Since discovering what is as close to a closed loop of information about the whole process, I’ve come to the conclusion that doing anything less than documenting it here would be just plain mean. As with all my posts, I do not pretend to be an expert in any of this, I am simply passing along observations as I find them:

CakePHP’s Concept of Basic Security is Essentially Wrong.

This was an unsettling one to come to, but there’s no other way around it. The Auth component is the component that handles allowing or disallowing access to things. Strictly speaking, since “Auth” means “Authentication,” according to the Cake Book, this is wrong. Authentication is the process of correctly identifying one’s self, which has nothing to do with whether or not the correctly-identified person has access to a given resource. “Authorization” is the process of granting and denying access  I realize that in many applications, simple authentication login/out type authorization works fine. But in the case of an application that uses both Auth and ACLs, Auth should properly surrender the authorization role and defer to the ACLs.

It does not. In fact, the ACLs don’t actually handle authorization at all, merely documenting the desired level of authorization. This is exactly opposite of the expected behavior. I realize now I will get comments telling me how very, very wrong I am about the whole business. But I don’t think I’ve forgotten that much about my Security+ certification.

Granting and Denying Access is Up to You

Right along with that, a quick explicit note: you will have to handle the granting and denying of access to actions/controllers/resources yourself with the Acl->check() function. If the user checks out, let ’em through. If they don’t, bounce ’em. Very explicit. I’ll get more into this further down the page.

Aliases are the Way of the (CakePHP ACL) World

Even though the alias field is an optional field for both ACOs and AROs, CakePHP still expects to be able to access the various elements through a sort of pseudo-alias, if such a term even makes sense. Instead of referring directly to the node’s ID – which lets face it, would get cumbersome – the ACL Component expects to refer to a combination of the model and foreign_key fields to identify it’s target node. I presume – read: have no first hand knowledge to the effect – that since the ACO table also includes the model and foreign_key fields, an ACO with no alias would also rely on this same pairing. Fortunately, while this is not documented really at all, once you know this it makes life a whole lot easier to simply grab user ID information out of the Session variables and go to town.

Weird and Significant: <node> and <node> are Not the Same Thing! (ta-da!!)

Did you run “cake acl help” only to find that both the grant() and deny() functions contain the ambiguous <node> parameters? Did you know which one is which? Me neither. The first parameter is the ARO node, whereas the second is the ACO node. Irritating vagueness in the help menu which if I can find the time, I will try to submit a patch for. ~ Update: I’ve submitted a patch to Lighthouse. They’re pretty quick assigning and updating patches, so assuming they agree with my assessment, it might even be updated in trunk by the time you read this!

There are Two Distinct Methods of Assigning Access

Those of us familiar with network security tend to think of ACLs in terms of limiting the CRUD access of users. CRUD stands for Create, Retrieve, Update, Delete. You can see these types of permissions in Windows Security properties of a file or folder, or in the standard chmod formulas most PHP developers know well, or in Mac file properties as well. It’s a fairly standard access schema.

In CakePHP’s ACL concept, each combination of ACO and ARO comes with it’s own standard set of these fields. Refer to the aco_aro table in your database for details. When you use the allow() and deny() functions, the last parameter refers to these fields. You can also provide additional fields to this database which can also be set where needed. A flag that allows access to admin routes on specific controllers, for example, would be handy.

The second method would be to assign ACOs to each public function in your controllers. You could explicitly list every action within every controller in your application. The CakePHP Book actually provides a nifty batching tool to help you do just that, albeit buried in a bunch of other stuff. This allows you much more explicit control of each function within your application.

Without an Explicit Reason, Using CRUD Fields is Better Than Using Actions

And if you really need to get right down in it – I mean, really specific to an exact function – this would be the way you would go about restricting access to a specific action. But generally, I find that most actions boil down to the basic CRUD concepts anyway.

That being the case, since CakePHP already provides you CRUD values for each association in the aros_acos table and as stated, a very explicit way of using them, why not just take advantage of what’s there? In the event that there is a specific function for which specific access needs to be granted – for example, one that does more than simply adding or deleting something from the database – then perhaps specifically calling out this action is required. The difficulty is that once you get down to these explicit actions, CakePHP’s Tree Behavior doesn’t really seem to work quite the way I’ve expected it to in the past. One would expect that, if the parent Controller is assigned a set of permissions and if the action is associated to the Controller as a child, the permissions would cascade down. Either I’m doing things wrong – entirely possible – or else it doesn’t really work that way.

Anyway, I hope this information proves clarifying or illuminating to some of you out there. If you have other questions, I can’t promise I’ll answer correctly, but please ask anyway in the comments. I’m sure corrections and modifications can be made along the way, so for those of you with greater knowledge than my own, I invite you to point out the flaws in the comments as well. Thanks!