[kforge-dev] How does the (new) access control system work?

John Bywater john.bywater at appropriatesoftwarefoundation.org
Thu Feb 2 22:15:25 UTC 2006

Rufus -

A good start, but it's a bit more complex than you wrote it. I'll try to 
refine without reproducing the code.

Rufus Pollock wrote:

> This is a work-in-progress intended to:
>   * help one understand how the access control system works
>   * check that my understanding (as presented here) is a correct 
> reflection of what we have
>   * to raise some questions about the current system and highlight 
> areas we might want to improve in future
> Protection objects:
> ===================
> We represent things to which we wish to control access via 
> ProtectionObjects (POs). There are several kinds.

As an aside, I prefer to name to association between a protected name 
and a set of protected objects as 'protection', rather than 

Anyway, there is just one kind of protection object. It's class name is 
'ProtectionObject'. Additionally, I would prefer not to use acronyms 
anywhere (except for a very restricted set, such as DB, which everbody 
knows stands for Deutshe Bahn).

However, protection objects have a name, which is referred to in the 
kforge code as a 'protected name'. The protected names describe the 
objects protected by the protection object. Protected names are currenly 
implemented as Python strings.

Because a protection object holds its protected name uniquely, we can 
safely talk about protection objects protecting the protected objects 
that are described by its protected name.

Anyway, there are two kinds of protected names:

1. Those describing a class of domain objects.

- the class is described with the name of the class

e.g. 'Project'

2. Those describing a instance of a class of domain objects.

- the instance of the class is described by appending the class names 
with a full-stop followed by the result of calling the method 
'getRegisterKey' on the domain object

e.g. 'Project.administration',
e.g. 'Service.14'

>   1. Those representing entire sets of domain objects such as Person, 
> Project, Member, Service, Plugin POs

I have a preference not to use the acronym PO, and to refer to the 
association as 'protection' rather than 'representation'.

>   2. Those representing application subsystems such as a subversion 
> repository or a wiki. These are correlated to an **instance** of the 
> plugin domain object to which they correspond. At present these POs 
> have the name 'Plugin.<instance-name>' and, for example, to get hold 
> of the subversion repository protection object we use the svn instance 
> of the plugin domain object.

No, the access control system has nothing so specific. As predicted from 
my definition above, the protected name for an instance of the class 
'Plugin' named 'eventlogger' would be 'Plugin.eventlogger'.

But there is no special treatment for application subsystems, or 
anything else.

At present we control access to Service instances by checking access to 
the Plugin class used for the service. In other words, when a service is 
accessed, the code checks whether or not the session person has access 
to the plugin class. But there is no reason why this couldn't be 
adjusted so that we control with instances of the Service (rather than 
the class of the service plugin) by firstly creating protection objects 
and granting a profile of permissions and then checking whether or not 
the session person has access to the session object.

>   3. 'Personal' POs corresponding to persons on the system. These are 
> accessed via the specific person instance e.g. using the admin Person 
> domain object you can get the 'Person.admin' PO. [ed: I am not clear 
> what these protection objects are used for at present. See question 
> below]

No, there is no such special treatment. As predicted from my definition 
above, the protected name for an instance of the class 'Person' named 
'levin' would be 'Person.levin'.

Perhaps it needs saying that a protected name such as 'Person.levin' 
would describe the instance of the 'Person' class which returns 'levin' 
from a call to its getRegisterKey() method (which here means that the 
'name' attribute has the string 'levin'). What is it used for? 
Specifically and exclusively "protecting" (in the sense of the above 
verb-association) the "levin Person" object.

> Permissions
> ===========
> Permissions are then made up of a protection object and an action. 

Yes. But we should know that a permission is something that needs to be 
given or refused in order to do something described by that permission. 
A permission is something that might not have been given or refused.

Instances of Role and Person can receive grants and bars. At a stretch, 
we can say that roles are granted and barred from permissions, and that 
a Person can act "in a personal capacity", or "in their own role". 
Anyway, the main concept implemented here is: "role".

> Presently possession of a permission is a grant (and its absence 
> implicitly a bar).

No. A permission can not be assigned, or it can be positively assigned 
(grant), or it can be negatively assigned (bar).

Currently, a permission can be assigned as a grant >and< as a bar to a 
Role (or Person). But this means they are barred.

If a permission is not assigned to a Role (or Person), that doesn't mean 
they are barred. It means they aren't barred or granted. If a person has 
no grant or bar and the access control is implemented to deny by 
default, then access will be denied.

> Roles
> =====
> Roles and persons then aggregate permissions.
> A person has:
>   1. A System Role: person.role
>   2. Individual grants and bars: person.grants, person.bars

....or a "Personal Role".

>   3. Memberships in various projects. Associated to each membership is 
> a role specific to that project. person.memberships[<project>].role

and "Membership Roles".

> Context
> =======
> Actions are performed by the user in a particular context.

Actions are performed on protected objects....

Or we can say "permissions are exercised". Or something other than 

Anyway, permissions are exercised by users....

> At present the only thing to count as context is the project in 
> relation to which an action is performed. 

No. In general we control access to the system. That is the first 
"context", although context isn't an implemented concept:

To control access to the system, we call on the SystemAccessController.

To control access to a project in the system, we call on the 

The ProjectAccessController knows about a Project, and so it can (and 
does) consider a possible Member of the Project by the Session Person. 
The SystemAccessController can only consider the "personal" role and the 
assigned system role.

> For example if I am trying to look at the list of members on project X 
> the context is project X.

This gives the impression that there is an object somewhere called context.

"For example if I am trying to look at the list of members on project X" 
then the Project X object will be passed to the ProjectAccessController, 
and its isAuthorised() method will be called your Person object as the 
person, with 'Read' as the action name, and with the 'Member' class as 
the protected object.

> How we do access control
> ========================
> Thus each activity which needs to be controlled is broken down into a 
> tuple consisting of:

There isn't a concept of activity defined in this discussion, or in the 

>   1. the person doing the action
>   2. the object on which they are acting
>   3. the action they are performing
>   4. the context

More like:


"Sections of presentation layer code are protected by calls to their 
access controller to check whether the session person can take one of a 
number of named actions with one of a number of protected objects."

> Thus suppose that user joe attempts to look at the list of members of 
> project foobar. This becomes:
>   (person=joe, ProtectionObject=member, Action=Read, 
> context=(project=foobar))

No, it doesn't. The view that lists members calls to the 
ProjectAccessController to see whether joe can Read Members. 
Importantly, the Member class is a >protected< object. The protected 
object is passed in from the presentation layer to its access controller.

> The access control system then a) creates a permission from the 
> ProtectionObject and Action b)checks whether the person has the 
> permission by doing the following in the order described:

This isn't clear. At one point, the access control system is configured 
by creating protection objects for protected objects and selectively 
assigning their permissions to roles. At a later point, access is 
controlled by checking whether a session person can take an action with 
a protected object. All the rest is the responsibility of the access 
controller, and the people who assign permissions.

>   1. is there personal bar? If yes: DENY
>   2. is there a personal grant? If yes: ALLOW
>   3. is there a system role grant? If yes: ALLOW
>   4. is there a context? If yes get the associated role. Does this 
> role have a grant? If yes: ALLOW
>   5. DENY

To clarify, the ProjectAccessController extends the 
SystemAccessController: The SystemAccessController takes steps 1-2-3-5, 
and the ProjectAccessController takes steps 1-2-3-4-5.

That is the ProjectAccessController extends the behaviour of the 
SystemAccessController by also checking for a role on the project.

But this isn't written as "context". There is no context object.

NB It doesn't make sense to have a concept of context in the access 
controller becaue there is no such general entity to assign permissions 
to. There is a system-role, and the system is refined with 
project-roles. The system presentation uses the SystemAccessController, 
unless this is overridden. It is overridden by the part of the kforge 
presentation which deals with objects of a project, which uses the 

> Remarks
> =======
> 1. System-wide and project roles are the same.

No, they can be different. But there is one set of roles from which to 
select. And a Person can only have one system role, and one role per 
membership of a project. They also have their own "personal role".

> However project role permissions will only be applied in the context 
> of a particular project. 

This isn't a very good way to think of, or to describe, the concern:

> Thus suppose the Friend role has read permission on the 
> ProtectionObject corresponding to a subversion repository. Then a 
> person who has the Friend role as a system role can read **all** 
> subversion repositories. If they have the role as a membership role, 
> say on project foobar, then they can only read foobar's subversion 
> repository.

Yes, as only as they no longer have that system role.

> 2. There is no support for differentiating access across the same 
> application subsystem on a project. For example you either have access 
> to all subversion repositories or to none. This may be something we 
> wish to look at in future.

As I described above, we can simply start to use the service as the 
protected object.

> Questions
> =========
>   * When are personal protection objects used? (Is it in relation to 
> updating your own profile? If so could we not use context? By this I 
> mean that when checking whether an update is permitted on a person we 
> include the context of who this person doing the action is, and, if 
> they are the same person, we give them admin rights)

We could create a PersonAccessController, to echo the "personal role" in 
the same way that membership roles are echoed in the 
ProjectAccessController, but then we're starting to repeat the DOM class 
system, which is a bad smell.

>   * Why do we need personal grants and bars? It would seem to make the 
> system simpler if they did not exist. (this may relate to previous item)

This is how we grant permission for somebody to update their own profile.

>   * looking at the ProtectionObject class it appears that the way it 
> is currently written a ProtectionObject protects both the 
> corresponding class object and its instances.

No. A ProtectionObject protects what is described by its protected name. 
There are two types of protected name. Only one type of protected name 
(the one without a "." in the middle) protects an entire class of 
objects. See above.

> Thus for example if we have the ProtectionObject 'Plugin' this will 
> protect both 'Plugin' (Plugin objects in general) and 'Plugin.svn' (a 
> subsystem application corresponding to subversion repositories).


> Similarly the 'Person' PO will cover both the set of persons and a 
> particular person.


> Is this the behaviour we really want.


> For example I might want to be able to allow people to read the list 
> of plugins on the system but that doesn't mean I want them to be able 
> to read all subversion repositories.

Well, if we want to make more distinctions, then we'll need to make more 
protection objects. To distinguish between Plugins and Services, we'll 
need to create both Plugin and Service objects.

If this basic foundation is clear enough, I think we should move on to 
reviewing what the roles names mean to people, how permissions should be 
assigned to the roles, and which objects should be used as the protected 
objects for the access checks. That's the real discussion.

I think we need another role: Enemy. Enemy can read / but nothing more. 
Then, Visitor also gets to read projects, create Person. Friend can read 
most stuff. Developer can also update somethings. Administrators can 

Then we should think of different levels of access. If the default 
visitor role is low, then registering will make more of the system 
visible. If system role is lower than default project role, then joining 
a project will make more a that project visible. If a default project 
role isn't the highest role, then some of project actions can still be 

Anyway, I hope this all makes sense.

Best regards,


More information about the kforge-dev mailing list