User Tools

Site Tools


soft:server-apps-permissions

Permissions Application

This app provides a framework for implementing permissions, integrating them with the admin interface (django.contrib.admin) and the authentication system (django.contrib.auth).

The pattern for implementing permissions is using a class based permission definition, with support for model-level as well as object-level rules.

Note that permissions app will auto-discover permissions defined on each app_name/permissions.py module.

Defining permissions

This is an example of how nodes/permissions.py file may looks like:

from __future__ import absolute_import
from permissions import Permission, ReadOnlyPermission, RelatedPermission
from .models import DirectIface, Island, Node, NodeProp, Server
 
 
# Inherit from Permission base class
class NodePermission(Permission):
    admins = ('group_admin', 'node_admin')
 
    def view(self, obj, cls, user):
        """ Everyone can view """
        return True
 
    def add(self, obj, cls, user):
        """ group and node admins can add """
        if obj is None:
            allow_nodes = user.groups.filter(allow_nodes=True).exists()
            return user.has_roles(self.admins) and allow_nodes
        if obj.group.allow_nodes:
            return obj.group.has_roles(user, roles=self.admins)
 
    def change(self, obj, cls, user):
        """ group and node admins can change """
        if obj is None:
            return user.has_roles(self.admins)
        allow_nodes = user.groups.filter(allow_nodes=True).exists()
        return obj.group.has_roles(user, roles=self.admins) and allow_nodes
 
    def delete(self, obj, cls, user):
        """ group and node admins can delete """
        if obj is None:
            return user.has_roles(self.admins)
        return obj.group.has_roles(user, roles=self.admins)
 
 
# Register the permission definition to the model where it belongs to:
Node.has_permission = NodePermission()
# Define permission for related objects (inherits node permissions)
NodeProp.has_permission = RelatedPermission('node')
# Readonly permissions (except superusers!)
Server.has_permission = ReadOnlyPermission()

Permission Program Interface

Following some examples of the permission interface we've just provided to Node:

from nodes.models import Node
 
# Check class permission by passing it as string
Node.has_permission(user, 'change')
 
# Check class permission by calling its method
Node.has_permission.change(user)
 
# Check instance permissions
node = Node()
node.has_permission(user, 'change')
node.has_permission.change(user)

Aggregate permissions

Pluggable applications can aggregate permissions to others using Permission._aggregate() method. For example:

# Define the permissions as usual
class FirmwarePermission(Permission):
    def getfirmware(self, obj, cls, user):
        if obj is not None:
            return obj.group.has_roles(user, roles=['group_admin', 'node_admin'])
        return False
 
# register
Node.has_permission._aggregate(FirmwarePermission())
 
# now you can use it as usual:
node.has_permission.getfirmware(user)

Permission backend

Also this permissions are supported through a Django compliant authentication backend defined at users.backends.TestbedPermissionBackend. Therefore User instances support queries like:

# Per object permissions
#             'app.action_model'
user.has_perm('tinc.add_tincclient', obj)
user.has_perm('nodes.view_node', obj)
user.has_perm('nodes.change_nodeprop', obj)
# Per model permissions
#             'app.action_model'
user.has_perm('slices.add_slice')
...

Admin interface support

Support for the admin interface is provided through a set of admin classes: PermissionModelAdmin, PermissionTabularInline, PermissionStackedInline and PermissionGenericTabularInline.

  • PermissionModelAdmin extends ModelAdmin class.
  • PermissionTabularInline extends TabularInline class.
  • PermissionStackedInline extends StackedInline class.
  • PermissionGenericTabularInline extends GenericTabularInline class. Enables the use of generic relations in forms and the admin.

These classes add support for view permission to the already existing admin built-in add, change and delete permissions.

from permissions.admin import PermissionModelAdmin, PermissionTabularInline
 
 
class NodePropInline(PermissionTabularInline):
    ....    
 
 
# If your admin classes uses multi-inheritance then 
# *usually* you want PermissionXxx to be called last
class NodeAdmin(OtherClass, PermissionModelAdmin):
    ....
soft/server-apps-permissions.txt · Last modified: 2014/05/21 10:51 by santiago