AD7six.com

Access Control for all (Part 1)

4 October, 2006

Show comments

So, you read the manual but how to put in place access control for the sensitive content of your site still eludes you. Have no fear, this post is for you. A while ago I wrote a descriptive blog on the difference between authentication and access control, it didn't go into code details but in it I mentioned that i would write a tutorial on ACL if the question was still floating around in the future - well here is that tutorial.

This blog will cover a few basic concepts and how to set up your application to permit access control, in the next part I will show how easy it is to administer your access control lists including a demo

All of the examples will be using nothing but core code (including the cake db acl solution itself), I hope that it is found to be useful. Enough! Let us begin..

Background

Granularity

The trouble with access control is that it's implementation is often project specific - what changes? Granularity.

Sometimes you want an on/off switch style access control (owner can do everything, public can only view public content), other times you want things to be controlled based on group rights, another time you want to be able to control things based on individual rights, and that's not even addressing what happens to the things you are controlling - do you want to be able to check if Users can edit all posts? Do you want to check if Bob can edit all posts? Do you want to check if Bob can edit all posts the he created? Do you want to check if Bob can edit section 2 of post number 217? Etc. How granular you make your access control is up to you.

The cost of ACL

Before implementing anything, it's a good idea to think about how to organize your access control such that the logic is simple, and the number of checks are few. It's then worth thinking about it again ;).

Access control isn't free - you are adding additional logic to your application and sending extra queries to your database (unless you use a file-based system, but I'm not going to address that in this article); all of this means extra time, and a poorly implemented ACL system can cripple your application.

There's also a management overhead, as somebody needs to make sure that users are assigned to the right groups (if appropriate) and ensure that they have, or inherit, the correct rights. This is covered in the next post on the topic.

Prerequisites

Authentication

To be able to check if a user can access something, before you can do anything, you need to know who the user is. If you already have some form of authentication system in place, skip on... still here? The purpose here is not to discuss authentication, but thankfully those boys over at CakePHP have already written a simple tutorial on how to put the most basic user authentication in place. If you follow this or a similar approach (DAuth from the bakery seems a more complete solution), then by checking for the presence of a particular session variable it should be possible to know if a user is logged in, and by reading the value you know who is logged in. So, that provides the answer of how to know who is logged in.

"You've gotta have a system"

It is important to be consistent regarding the names for your aros(users/groups/roles) and acos so that the code doesn't need convoluted logic to be able to ask the question "can the current user access this url". What that system is is up to you but if you use a convention, it should then be easier to understand and code how you are going to put access control in place. So here's a suggestion which will be used in this and subsequent posts on the topic:

  • the aro used for acl checks is the current user name in lower case.
  • aros related to groups or roles will be in upper case.
  • the "action" (3rd parameter for the acl queries) will always be "*"
  • acos will be named following the syntax "section:controller:method:parameter1:parameter2" (also lower case and underscored if appropriate.)
  • The parent of an aco named "x:y:z" will be named "x:y" etc.
  • There is only one aco with no parent and that is the aco named "ROOT"

Section refers to the part of the application that is being accessed, in reality that means the name of the plugin or the name of the App folder.

Setting up your app to use Access control

Let's make a couple of assumptions.

  • You have one website administrator and only this user has access to /admin/ urls.
  • An unidentified user will have the same rights as the aro 'PUBLIC'
  • access control will be added to every url (removing acl for an individual controller will be covered a little later).

How can this be achieved? Quite simply by including the AC (access control) component, which is shown below:

Note that for easy debugging you are not automatically redirected in this way if your DEBUG setting is greater than 0 - as such never use DEBUG on a live system. I wrote about changing the config at run time before and it can be used to great effect to investigate what is happening on a live system without affecting other users; you can even use the same approach to turn ACL on and off to simplify debugging tasks. It may be useful to write to a log file in the aclLog method, so that keeping track of what is happening is possible.

Great but if it's all automatic, what if I need to change something?

This question is likely to be one of the first on your lips. If you take a look at the component code, it has 2 features which should account for any deviation from how it acts by default.

Different ACO names for a controller

You can change the way aco names are determined by defining the method _getAcoAlias in your controller. Take a look at this snippet from a pages controller to see how you can make use of that:

Isn't that beautiful? By overriding the method for determining the ACO alias, it is possible to change the ACL check to be meaningful without excessive code.

Bypassing the ACL check for a controller

You can cause the AC component to ignore access to a controller by defining the var publicAccess in the controller and giving it the value 'true'.

Conclusion

The goal of this blog was to explain how to integrate ACL checks into your app I hope that was achieved. The next post on the topic covers how to administer your AROs, ACOs and ACL rules - without writing code yourself to create the objects, and with the flexibility to define the rules as you wish. Did I mention the demo enough times? :)