Declaring our data access rules declaratively.

1

January 30, 2013 by thisisjedimike

Django-group-access is an app for django that controls row-level access to data based on group membership. This was perfect for a few projects we were developing in Canonical. So perfect, in fact, that we wrote django-group-access, and open sourced it.

It does a few nifty things. And these nifty things got us out of a tight spot where we had to redefine access control rules at short notice.

1) Declare access control rules, instead of having to code them in your views.

This means that if you want to control access to instances of MyModel, you just have to declare that MyModel is access controlled. MyModel will automatically pick up all the attributes needed to share it with groups, and have a user take ownership of it. It’s as simple as:

from django_group_access import register
from myapp.models import MyModel

register(MyModel)

2) Optional middleware will automatically filter your querysets so your views do not have to be aware of access control.

In some access control apps (admittedly, ones that are more focussed on providing row-level permissions, rather than row-level access) you have to modify your code and models to be aware of the access control. For example, you might have to do something like this:

def my_view(request):
    records = MyModel.objects.accessible_by_user(request.user).all()

That could be a lot of work if you’re integrating it into an existing app, and prohibitive if you’re integrating into a third party app.

With the automatic filtering in django-group-access, it remains:

def my_view(request):
    records = MyModel.objects.all()

That would give you all the records that the currently logged in user has access to. Plus, at no extra charge, it includes the .unrestricted method to give you unfiltered access to a queryset, like this:

def my_view(request):
    # all the visible records for the current user
    records = MyModel.objects.all()
    # all the records that exist
    all_records = records.unrestricted()

3) It allows you to create a hierarchy of models that control access.

Say you had a Room model, and a House model. If you had access to a Room, you want access to the House too.

With django-group-access, that’s easy.

class House(models.Model):
    address = models.TextField()

class Room(models.Model):
    description = models.TextField()
    house = models.ForeignKey(House)

register(Room)
register(House, control_relation='room')

Now, because django-group-access allows us to declare access rules instead of coding them into the models, and because it does automatic filtering, changing how the visibility of records is worked out becomes as easy as changing how your models are registered, and migrating your schema. (And, of course, changing the test data that your extensive unit and integration tests, set up. That’ll teach you to use test data factories…)

Development on django-group-access is ongoing, with plans for django-access-tng which will include row-level permissions and finer grained access control that doesn’t need to share records with groups to grant access.

But pretend you didn’t read that last paragraph. Our current product is the best. The new one might never come. Buy now to avoid disappointment.

One thought on “Declaring our data access rules declaratively.

  1. maxirobaina says:

    Hi,
    Nice app. Thanks for sharing.
    It gave me some ideas for another things.

    Regards.
    @maxirobaina

Leave a comment