[kforge-dev] How does the (new) access control system work?
John Bywater
john.bywater at appropriatesoftwarefoundation.org
Thu Feb 2 22:16:33 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
'representation'.
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
'exercise'.
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
ProjectAccessController.
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
code....
>
> 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:
controller-person-action-object
"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
ProjectAccessController.
>
> 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).
Yes.
> Similarly the 'Person' PO will cover both the set of persons and a
> particular person.
Yes.
> Is this the behaviour we really want.
Yes.
> 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
create/delete.
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
reserved.
Anyway, I hope this all makes sense.
Best regards,
John.
More information about the kforge-dev
mailing list