Overview
As explained before capabilities permission system provide access to objects only based on a Share. This element provide: an identifier (uuid), a set of allowed actions to users (aka Capability), and eventually an expiration date.
This figure shows how is it implemented in Django-Caps:
The Object is accessed through its Share. A Share is assigned to an Agent which identifies the user. The Share provides capabilities which are linked to Django’s auth Permission.
Django-Caps provides views that will use the provided scheme in order to grant user access or actions.
Object, Share,
Capability models are abstract. When Object is subclassed in a concrete model,
a concrete Share is generated (accessible from subclass scope). The same occurs between Share and Capability.
This mechanism ensure different things:
The Share and Capability models are associated to one object type, allowing reverse relations to be accessible (comparing for example over a solution using ContentType framework);
This ensure clear segregation for Shares and capabilities per object type and reduce tables sizes;
We can exploit this mechanism for eg. default Share capabilities;
Capability
A Capability represent a single action or access to be granted. It also can grant sharing this permission. It can in
some way be looked as a through table of a Django’s ManyToManyField although it not implemented as is
(due to technical reasons).
A default capability is the one provided by default when creating a root Share. It is simply a capability without an assigned Share. Since a Capability table is created for each Object concrete sub-model, we are sure they will only target this sub-model.
When user derives a Share, eg for allowing Alice to access the object, he can provide her the ability to reshare it
using max_derive provide the maximum amount of derivation as an absolute
value relative to root. Each time a Share is derived, the max_derive is decremented by one. This implies that:
..code-block:: python
access = Share.objects.all().first() capability = access.capabilities.all().first()
- if capability.max_derive == 1:
# this means that derived capability can’t be reshared assert capability.derive().max_derive == 0
- elif capability.max_derive == 0:
# this raises PermissionDenied, as capability can’t be derived capability.derive()
- else:
# this means that derived capability can’t be shared assert not capability.derive(0).can_derive()
# this means that derived capability can be reshared, as max_derive > 1 assert capability.derive(1).can_derive()