[kforge-dev] Access control code: refactoring and simplifying

Rufus Pollock rufus.pollock at okfn.org
Tue Jul 4 18:46:21 UTC 2006

Below are some observations on the access control code and how it could 
be improved. If people are happy with the suggested changes i am happy 
to be responsible for implementing them in the next iteration(s).



= Access control code: refactoring and simplifying =

A while back I discovered a bug in our authorization system whereby a 
logged in user could not access a project of which he/she was a not a 
member even though visitor could (ticket:??).

After a couple of hours debugging (and adding tests) I tracked this to 
accesscontrol.py. Having worked through that code and corrected the bug 
I think we should try to simplify the access control system. In 
particular I would suggest:

== 1. removing personal grants and bars ==

These are only present to address the issue of allowing users to edit 
their own profiles. This problem could be addressed in just two or three 
lines of code and would allow the domain mode to be simplified as well

Combination of grants, bars and normal RBAC is confusing:
   * what happens if a user has a grant to object A, a bar on object A and
   a role that permits access to object A? (Answer: access allowed)
   * what happens if a user has a grant on object A, a bar on object A?
   (Answer: access denied)
   * etc ...

== 2. Disambiguate meaning of service ==

It is confusing that an example service object in project annakarenina 
is just the service object (and therefore readable) but the example 
plugin in the context of that project represents the subsystem 
application and is *not* readable. We need some way to clearly 
disambiguate a service domain object and the running application 
(subversion repository/moinmoin wiki etc) which that represents both in 
our general discourse and as protection objects in the access control 

== 3. Reduce the repetition in access control code and tests ==

This repetition has grown up partly as a result of the natural accretion 
of code as development has progressed. Having several seperate layers 
each wrapping the one below but makes it hard to work out the logic of 
what is going on.

For example:
   * apache.urlpermission.isAccessAllowed calls
   * accesscontrol.ProjectAccessController.isAuthorized implicitly calls
   * core.accesscontrol.AbstractAccessController.isAuthorized calls
   * accesscontrol.ProjectAccessController.hasAuthorizedRole uses
     * accesscontrol.SystemAccessController.hasAuthorizedRole
     * accesscontrol.ProjectAccessController.isProjectRoleAuthorized

We also have:
     * core.accesscontrol.AbstractAccessController wraps 
core.command.AuthoriseAccess command converting exception into False
     * this is then reused by AccessControllers in accesscontrol.py
     * Next layer of commands in accesscontrol.py then rewraps this true 
or false back into No Exception (OK)/Exception (Not OK)

Do we really need all these separate layers? Probably not. specifically

   1. Why do we need the wrapper commands accesscontrol.py? 
(Is...ActionObjectAuthorised) Why not just use 
accessController.isAuthorized direct?

   2. Why don't we just override isAuthorised rather than 
hasAuthorisedRole. If we need to validate input (which is the generic 
thing done in AbstractAccessController.isAuthorised why not do this in 

   3. Why have logging in base class and in inheriting class saying 
similar stuff?

   4. why use person /object/, protected /object/ but /name/ of action?

== Suggest we change to the following ==

class AuthorizeAccess(Command)

     def __init__(self, person, action, object, context=None)
         # deal with defaulting (e.g. no person then make them visitor ...)

     def execute(self):
         # to be overridden

     def isAuthorized(self):
         # wrapper on execute to return True and False

class AuthorizeSystemAccess(AuthorizeAccess):

     def execute(self):
         # insert exception for person editing themselves
         # get system role and do access

class AuthorizeProjectAccess(AuthorizeAccess):

     def execute(self):
         # do AuthorizeSystemAccess
         # do AuthorizeAccess with person = visitor
         # if self.person != visitor
         #   do AuthorizeAccess with person = self.person

More information about the kforge-dev mailing list