Login

Support for permissions for anonymous users in django ModelBackend

Author:
jb
Posted:
November 8, 2011
Language:
Python
Version:
1.3
Score:
1 (after 1 ratings)
Model backend that enables permissions for AnonymusUsers.

I wanted it to be as simple as possible so anonymous users just forward their permission checks
to some fixed user model. This instance can be edited via django admin, assigned to groups, etc.

To control which user will represent anonymous user you use ANONYMOUS_USER_NAME setting in
settings file.

To provide some sensible level of security i enforce following for user that represents
anonymous user:

    * This user must have password equal to UNUSABLE_PASSWORD
    * This user may not log in
    * You cant cange password for this user via admin.

You need to enable this backend by setting AUTHENTICATION_BACKENDS. Please note that you 
should not place this backend alongside django ModelBackend. This backend inherits from it.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# -*- coding: utf-8 -*-
"""
    Model backend that enables permissions for AnonymusUsers.

    I wanted it to be as simple as possible so anonymous users just forward their permission checks
    to some fixed user model. This instance can be edited via django admin, assigned to groups, etc.

    To control which user will represent anonymous user you use ANONYMOUS_USER_NAME setting in
    settings file.

    To provide some sensible level of security i enforce following for user that represents
    anonymous user:

        * This user must have password equal to UNUSABLE_PASSWORD
        * This user may not log in
        * You cant cange password for this user via admin.
        
    You need to enable this backend by setting AUTHENTICATION_BACKENDS. Please note that you 
    should not place this backend alongside django ModelBackend. This backend inherits from it. 
"""
__author__ = 'jb'

from django.conf import settings
from django.contrib.auth.models import User, UNUSABLE_PASSWORD, Permission
from django.contrib.contenttypes.models import ContentType
from django.db.models.signals import pre_save
from django.dispatch.dispatcher import receiver

from django.contrib.auth.backends import ModelBackend

import logging
_LOGGER = logging.getLogger(__name__)

def get_anon_user_name():
    return getattr(settings, "ANONYMOUS_USER_NAME", None)

class AnonymousUserBackend(ModelBackend):

    def get_all_permissions(self, user_obj):
        if user_obj.is_anonymous():
                if not hasattr(user_obj, '_perm_cache'):
                    anon_user_name =  get_anon_user_name()
                    anon_user, created = User.objects.get_or_create(username = anon_user_name, password = UNUSABLE_PASSWORD)
                    user_obj._perm_cache = self.get_all_permissions(anon_user)
                return user_obj._perm_cache
        return super(AnonymousUserBackend, self).get_all_permissions(user_obj)

    def authenticate(self, username=None, password=None):
        if username == get_anon_user_name():
            return False
        return super(AnonymousUserBackend, self).authenticate(username, password)

    def has_perm(self, user_obj, perm):
        if not user_obj.is_active and not user_obj.is_anonymous:
            return False
        return perm in self.get_all_permissions(user_obj)

@receiver(pre_save, sender=User)
def disable_anon_user_password_save(sender, **kwargs):
    instance = kwargs['instance']
    if instance.username == get_anon_user_name() and instance.password != UNUSABLE_PASSWORD:
        raise ValueError("Can't set anonymous user password to something other than unusable password")

def register_custom_permissions(permissions, appname):
    ct, created = ContentType.objects.get_or_create(model='', app_label=appname,
                                                        defaults={'name': appname})

    for codename, name in permissions:
        p, created = Permission.objects.get_or_create(codename=codename,
                        content_type__pk=ct.id,
                        defaults={'name': name, 'content_type': ct})

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 3 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 11 months ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 7 months ago

Comments

Please login first before commenting.