Django PRBAC Tutorial

Models of class |Role| represent capabilities, which may intuitively map to users, privileges, groups, and collections of privileges.

Models of class |Grant| represent adding a user to a group, including a group in another group, and granting privileges to a user or group.

Users

This library does not replace or modify the Django user system – too many projects muck around with that, so it is safer and more flexible to leave it alone. Instead, you may give each user a corresponding |Role|:

>>> from django.contrib.auth.models import User
>>> for user in User.objects.all():
        Role.objects.create(
            name=user.username,
            slug=user.username,
            description='Role for django user: %s' % user.username
        )

This is very easy to automate with triggers or via the UserProfile feature of Django.

Privileges

A privilege is an actual thing that a user may do in the system. It is up to you to decide what these are and give them meaningful names and descriptions. For example, perhaps there is a granular permission of “may view reports”:

>>> may_view_reports = Role.objects.create(name='may_view_reports', slug='may_view_reports', description='May view reports')

>>> biyeun = Role.objects.get(name='biyeun')
>>> kenn = Role.objects.get(name='kenn')

>>> Grant.objects.create(from_role=biyeun, to_role=may_view_reports)

>>> biyeun.has_privilege(may_view_reports)
True

>>> kenn.has_privilege(may_view_reports)
False

All of this is normal for RBAC (without parameterization) but with PRBAC we can make this privilege more granular:

>>> may_view_report = Role.objects.create(name='may_view_report', slug='may_view_report', parameters=set(['report_name']))

>>> Grant.objects.create(from_role=biyeun, to_role=may_view_report, assignment={'report_name': 'active_users'})
>>> Grant.objects.create(from_role=kenn, to_role=may_view_report, assignment={'report_name': 'submissions'})

>>> biyeun.has_privilege(may_view_report.instantiate({'report_name': 'active_users'}))
True

>>> biyeun.has_privilege(may_view_report.instantiate({'report_name': 'submissions'}))
False

>>> kenn.has_privilege(may_view_report.instantiate({'report_name': 'active_users'}))
False

>>> kenn.has_privilege(may_view_report.instantiate({'report_name': 'submissions'}))
True

Groups

A group of users may be represented as a |Role| as well:

>>> dimagineers = Role.objects.create(name='dimagineers', slug='dimagineers', description='Dimagi Engineers')

>>> Grant.objects.create(from_role=kenn, to_role=dimagineers)
>>> Grant.objects.create(from_role=biyeun, to_role=dimagineers)

Now both kenn and biyeun are members of role dimagineers.

>>> kenn.has_privilege(dimagineers)
True
>>> biyeun.has_privilege(dimagineers)
True

But groups can also be useful when parameterized, for granting a variety of parameterized privileges to a group of people.

>>> may_edit_report = Role.objects.create(
        name='may_edit_report',
        description='May edit report',
        slug='may_edit_report',
        parameters=set(['report_name']),
    )
>>> report_superusers = Role.objects.create(
        name='report_superusers',
        description='Report Superusers',
        slug='report_superusers',
        parameters=set(['report_name']),
    )
>>> Grant.objects.create(from_role=report_superusers, to_role=may_edit_report)
>>> Grant.objects.create(from_role=report_superusers, to_role=may_view_report)
>>> Grant.objects.create(
        from_role=kenn,
        to_role=report_superusers,
        assignment={'report_name': 'dashboard'},
    )
>>> kenn.has_privilege(may_view_report.instantiate({'report_name': 'dashboard'}))
True
>>> kenn.has_privilege(may_edit_report.instantiate({'report_name': 'dashboard'}))
True