Access control in Django, and django-authority

The past week I've been working with Django and permissions. I'll talk here about the available options and go into details about the one Kitsune is using.

Here are the options I looked at:

Django's default permissions

Read more about this in Django's documentation.

Django provides a convenient and easy to use permissions system. The documentation covers it all, so I'm just going to summarize the pros and cons:

Pros:

  • Comes with Django (=> robust, well-written and stable)
  • Permission functions attached to the user object
  • Per-group permissions and per-user permissions
  • Model-level (a.k.a. per content_type) permissions (can add custom model-level permissions as well)
  • Work with Jinja templates, simply use user.has_perm('perm_name')

Cons:

  • No per-object permissions

AMO's access app

AMO's access app adds some flexibility on assigning permissions with wildcards and also stores the user's groups in request.groups.

Pros:

  • Flexible way to assign all permissions in a certain group
  • Does not store permissions in the models Meta class

Cons:

  • Replaces django's permission system (either use one or the other)
  • No per-object permissions

To use this, you can do something like this in your views:

from access import acl

# ...

def some_view_action():
    acl.action_allowed(request, 'Group', 'PermissionName')

django-authority

django-authority was the most promising of the three. It adds per-object permissions and wraps Django's default permissions system without forcing an either-or choice. It also has a decent documentation, and although still in draft at the time of this writing, it was enough for me to figure out how to use.

Pros:

  • Per-object permissions
  • Wraps Django's default permissions system, so you can use both
  • Custom permissions
  • Add permissions to appname/permissions.py, so they are completely separate from the models (unlike Django's permissions)

Cons:

  • Needs a bit of work to hook in with Jinja templates
  • Admin functionality not yet complete - the admin form generated by the edit_permissions admin action does not work at the time of this writing. The alternative is not too bad however, you can manually add to the Permission model using that model's admin.

django-authority on Kitsune

We are currently focused on rewriting SUMO's discussion forums. For Kitsune, we have multiple forums and we wanted the ability to have different forum moderators per forum. We're also using Jinja. django-authority comes with default Django template support, so if you're using that, you don't need to write your own template functions/filters.

For Jinja support, just add this to some app's helpers.py

import jinja2
from jingo import register
import authority

# ...

@register.function
@jinja2.contextfunction
def has_perm(context, perm, obj):
    """
    Check if the user has a permission on a specific object.

    Returns boolean.
    """
    check = authority.get_check(context['request'].user, perm)
    return check(obj)

Then, in your templates, you can just use:

{% if has_perm('perm_cls.codename_model', object) %}
{# grats, you've got the perms! #}
{% endif %}

See this link for more information on the perm_cls and codename variables.

If you're interested, here's the Kitsune code.

Hope that helps others who may decide to go this route. Questions and suggestions for improvement are always welcome, of course.