Showing posts with label permissions. Show all posts
Showing posts with label permissions. Show all posts

Thursday, February 21, 2013

Permissions and Capabilities

Users are a central concept to any software system. Even single-user systems have users, maybe even multiple users, just never at the same time. Looking at the user concept through the eyes of a developer, however, roles are a better concept. The reason is simple — roles are abstract where a user is an instance of one role or another. This is how we think about most other things in the system, so why not the actors that we're interacting with too? We're not interested in the user who is currently interacting with the system, because that's not how the UI components are designed. They're designed around roles. The role describes for the developer, what this user instance is capable of doing. Roles are about permissions and the underlying capabilities of system. The two are interrelated, but when separated, as they so often are, cause major headaches in the code.

Friday, November 4, 2011

Dealing With Permissions In Generic Views

Generic views in Django cover a vast range of usage scenarios. That's why they're called generic views — because they implement the abstract patterns common to most applications that are using views. This a huge savings on code-writing cost because there isn't as much of it to write — or maintain thereafter. So, this all well and good, but what about the pre-generic days of writing Django views? Is there nothing of value there we can carry forward and exploit in our newly-fashioned generic views?

Of course, before we used class based views, there were still some degree of generic capabilities that could be attached to our view behavior. They came in the form of decorators. Decorators in Python are a realization of the decorator pattern — we're attaching additional responsibilities to the function. Or, in this case, our view function. But things aren't so straight forward in the brave new generic world of writing views that use classes. How can we deal with things like permissions in our generic views while still honoring the DRY principle?

The decorated permission approach
The authentication system that ships with Django includes the ability to only expose certain views to specific users.  If we're writing views as functions, the authentication framework has decorators we can use to ensure the current user has the appropriate permissions.  Like this...

from django.shortcuts import render_to_response
from django.contrib.auth.decorators import permission_required

@permission_required('my_app.can_do_stuff')
def my_view(request):
    return render_to_response('my_template.html', dict())

This is an elegant approach to ensuring that only authorized user have access to my_view.  Since the permission_required decorator is provided by the authentication framework, it's available for every view in our application.  And, we only need to implement one line of code where we need to handle permissions. One per view.

The trouble with permission_required in modern Django applications is that they don't fit in nicely with the newer class-based generic view methodology.  So how then, can we exploit the power of the generic views in Django while keeping the simplicity of the decorated permission handling?

The inherited permission approach
One thing that class-based views offer that decorators don't is the ability to define defaults that the rest of the view hierarchy in our application can inherit.  These defaults include both data attributes and behavior.  This is one approach we can use with our class based views to simplify permission handling...

from django.views.generic import TemplateView
from django.http import HttpResponseForbidden

class MyAppTemplateView(TemplateView):
    
    perms = dict()
    
    def dispatch(self, request, *args, **kwargs):
        
        perms = self.perms.get(request.method.lower(), None)
        
        if perms and not request.user.has_perms(perms):
            return HttpResponseForbidden()
        
        parent = super(MyAppTemplateView, self)
        return parent.dispatch(request, *args, **kwargs)
        
class MyAppNews(MyAppTemplateView):
    
    template_name = 'news.html'
    perms = dict(
        get = ('myapp.can_see_news',)
    )

With this approach, able to control permission-based access based on the HTTP method — all within a dictionary overridden by descendant classes.  Here is how it works.

First, we're re-creating the base TemplateView class — called MyAppTemplateView.  Any other template views used in my application are now going to inherit from this class instead of the standard TemplateView defined by Django.  This is how we decorate each view with the added responsibility of ensuring access control.

The dispatch() method is the first call to action for any generic view.  So it is here that we want to approve of any additional execution.  What were doing here is really simple.  We're checking if the user has the permissions defined by the perms attribute.  And this is all we need to override.  By default, this attribute is an empty dictionary — so no permissions will be validated.

The MyAppNews view simply overrides the perms attribute to ensure the requesting user has the myapp.can_see_news permission.  It's not exactly a decorator, but we're retaining some flexibility while staying true to the DRY principle.

Saturday, January 10, 2009

ECP permissions

Permissions in the ECP system uses the CRUD permission architecture. The permissions for any object with a UUID may be validated for create, read, update, delete operations. One benefit to the CRUD architecture is that it maps well to a RESTful architecture.

In ECP, there is a permissions table that has three columns; u_uuid, t_uuid, and perms. The t_uuid column is the target object. The u_uuid is the user column. The perms column represents the CRUD permissions on the target object. The queries executed on this table are generally quite fast. We can simply query the table for the target object, user, and permissions. If any results are returned, we know that the user has permission on the object.

This table is actually created at ECP install time by the permissions_fast extension module. This module defines hooks that replace the identity framework method of checking permissions. It replaces the default functionality with the quires described above. Perhaps in the future, these queries should be the default functionality since the permissions_fast extension module is installed and enabled by default.

Friday, July 25, 2008

Enomalism permissions

The current development version of Enomalism (Beta 3), has some interesting permission enhancements in sight. First and foremost, the correct permission validation is almost completely implemented. Second, selecting sets of objects based on permission, as well as other constraints, has been implemented and is being fitted within the application as I write this. This will no doubt result in some performance enhancements which is just a side effect. The main reason it was introduced was to simplify the retrieval of objects that satisfy specified permissions.