Every now and then I see questions about ACL and how to use it. A lot of web developers are using it without actually knowing what it is and how it works, even though it’s powering one of the most important part of applications – user access management. So this series will explain that from raw basics to complete implementation with Zend Framework component Zend_Acl.
What is ACL?
ACL is the last step you make with implementing users’ access control – you first start with basic PHP website, then add login for users to post comments, then you create admin interface for administrators, some user groups to access private data etc. Probably you’ve seen code like this:
if ($user->type == ADMIN) { $html .= '<a href="/index.php?delete=' . $id . '"></a>'; }
It works fine, but the problem is that it becomes very difficult to extend as all access rules are stored in places all over the code, hence changing it isn’t that easy. It’s also not “correct”, as with all things in programming, things (logic) should be encapsulated. This problem is solved by using ACL, which makes code to look like this:
if (user_can($user, 'page', 'delete')) { $html .= '<a href="/index.php?delete=' . $id . '"></a>'; }
This code does exactly the same, but actual permissions logic is hidden (encapsulated) inside. It’s very clear what it is doing – can user $user execute delete on page? It doesn’t show that ACL is used at all, but this is a first step towards right direction.
Outside code shouldn’t care how these permissions are being calculated, as long as that one entry point is used (in this case a function user_can) pretty much any logic can lie inside, even the same as shown in first example, but when needed a proper ACL layer can be added, so lets look at that.
Basics
ACL stands for “Access control list” and it is a system designed to deal with any complexity permissions specifications. ACL systems consist of three basic components: roles, resources and permissions. They form a graph and are as follows:
- Roles – “admin”, “editors” etc. User has one or more roles, depending on architecture.
- Resources – “product#123″, “categories” etc. It’s just an object which is controlled by ACL.
- Privileges – “list”, “delete”, “create” etc. Actions role can perform on resource.
Once you have these components defined you can start forming relations. For example, string “admin can delete products” can be seen as: role “admin” has privilege “delete” on resource “products”.
One thing to understand from this is that all 3 components are very dynamic – I don’t know about any situation where ACL cannot be applied, it’s only a matter of understanding how it works. For example Zend_Acl relies on you for constructing ACL tree, so DB backend, lazy-loading etc. should be created yourself, that’s why it’s too hard to start with and why I’m writing this in a first place.
Web
MVC is very easy to use with ACL, as you have a very clean separation of resources – every controller (or controller and module) is a resource and privileges are usually controllers’ actions. For example products controller can have “list”, “add”, “edit” and “delete” actions and those clearly are permissions on products resource.
$acl->isAllowed($user, $request->getController(), $request->getAction());
Looks very clean and logical. Of course direct mapping from controller/action name to resource and privilege is not perfect; ideally you should construct some Zend_Acl_Resource object from request data and check on it. As you will see in later posts, you can use same logic to auto-generate menus only including links user can actually see.
Quite commonly resources are much smaller and represent actual objects in system – news item, product, comment etc. Some users can only delete their own comments, where user belonging to sport news admin group can delete any in that category. Even though these rules are very different for different apps, but actual ACL implementation is pretty much the same – just create resources for each object (or lazy load) and add some permissions logic depending on requirements.
Problems
ACL management is problematic when you do not have GUI for that. This is because ACL is a complicated graph and just by looking at the code it’s very hard to understand how all elements are connected to each other.
One of the biggest causes of problematic ACL is the fact that it supports inheritance and privileges have weird inheritance by themselves (I don’t know how much of this applies to ACL in general; later observations are mainly based on Zend_Acl behaviour). For example if role has access to resource with permission “null“, user can access resource with any permission (even if there is no information about it). Whereas with resources, ACL system checks parent resource until it finds allow/deny.
Because of those issues, one of the first things I recommend doing is… unit test. It’s not that hard, but can help you to understand how everything works and if in fact ACL tree represents your required logic. Once you know that it does work in backend, create user interface (like seen in many CMS systems) to make management easy and clean. Ideally you shouldn’t touch it once it’s created.
Conclusion
ACL is very powerful system (if your library supports all features of course), although it’s definitely not the easiest one to work with. In next posts of this series I’m going to look at actual implementations and how to make use of them.
All parts:
Zend Framework is always considered as being the slow/bloated one. I don’t think this is right, so I decided to prove that it’s not correct and in fact ZF is as good as other frameworks are. This post doesn’t cover any benchmarks though; this is more like a architecture review and some misconceptions disproof.
While attending 

During last two months I spent massive amount of time tweaking Doctrine ORM framework and making it to perform as fast as possible (as you might have noticed from my never ending 

It’s been more than a month since this competition started, but the time ran very quickly. Today I’m going to summarize what I’ve used to create my entry and what I’ve learned.







