OpenSlides/openslides/users/auth.py
2015-06-29 15:15:33 +02:00

146 lines
5.2 KiB
Python

from django.contrib.auth import get_user as _get_user
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.context_processors import auth as _auth
from django.contrib.auth.models import AnonymousUser as DjangoAnonymousUser
from django.contrib.auth.models import Permission
from django.db.models import Q
from django.utils.functional import SimpleLazyObject
from rest_framework.authentication import BaseAuthentication
from openslides.core.config import config
class AnonymousUser(DjangoAnonymousUser):
"""
Class for anonymous user instances, which have the permissions from the
Group 'Anonymous' (pk=1).
"""
def get_all_permissions(self, obj=None):
"""
Return the permissions a user is granted by his group membership(s).
Try to return the permissions for the 'Anonymous' group (pk=1).
"""
perms = Permission.objects.filter(group__pk=1)
if perms is None:
return set()
# TODO: test without order_by()
perms = perms.values_list('content_type__app_label', 'codename').order_by()
return set(['%s.%s' % (content_type, codename) for content_type, codename in perms])
def has_perm(self, perm, obj=None):
"""
Check if the user has a specific permission
"""
return (perm in self.get_all_permissions())
def has_module_perms(self, app_label):
"""
Check if the user has permissions on the module app_label
"""
for perm in self.get_all_permissions():
if perm[:perm.index('.')] == app_label:
return True
return False
class CustomizedModelBackend(ModelBackend):
"""
Customized backend for authentication. Ensures that registered users have
all permission of the group 'Registered' (pk=2).
"""
def get_group_permissions(self, user_obj, obj=None):
"""
Returns a set of permission strings that this user has through his/her
groups.
"""
# TODO: Refactor this after Django 1.8 release. Add also anonymous
# permission check to this backend.
if user_obj.is_anonymous() or obj is not None:
return set()
if not hasattr(user_obj, '_group_perm_cache'):
if user_obj.is_superuser:
perms = Permission.objects.all()
else:
user_groups_field = get_user_model()._meta.get_field('groups')
user_groups_query = 'group__%s' % user_groups_field.related_query_name()
# The next two lines are the customization.
query = Q(**{user_groups_query: user_obj}) | Q(group__pk=2)
perms = Permission.objects.filter(query)
perms = perms.values_list('content_type__app_label', 'codename').order_by()
user_obj._group_perm_cache = set("%s.%s" % (ct, name) for ct, name in perms)
return user_obj._group_perm_cache
class AuthenticationMiddleware(object):
"""
Middleware to get the logged in user in users.
Uses AnonymousUser instead of the django anonymous user.
"""
def process_request(self, request):
"""
Like django.contrib.auth.middleware.AuthenticationMiddleware, but uses
our own get_user function.
"""
assert hasattr(request, 'session'), (
"The authentication middleware requires session middleware "
"to be installed. Edit your MIDDLEWARE_CLASSES setting to insert "
"'django.contrib.sessions.middleware.SessionMiddleware' before "
"'openslides.users.auth.AuthenticationMiddleware'."
)
request.user = SimpleLazyObject(lambda: get_user(request))
class AnonymousAuthentication(BaseAuthentication):
"""
Authentication class for the Django REST framework.
Sets the user to the our AnonymousUser but only if
general_system_enable_anonymous is set to True in the config.
"""
def authenticate(self, request):
if config['general_system_enable_anonymous']:
return (AnonymousUser(), None)
return None
def get_user(request):
"""
Gets the user from the request.
This is a mix of django.contrib.auth.get_user and
django.contrib.auth.middleware.get_user which uses our anonymous user.
"""
try:
return_user = request._cached_user
except AttributeError:
# Get the user. If it is a DjangoAnonymousUser, then use our AnonymousUser
return_user = _get_user(request)
if config['general_system_enable_anonymous'] and isinstance(return_user, DjangoAnonymousUser):
return_user = AnonymousUser()
request._cached_user = return_user
return return_user
def auth(request):
"""
Contextmanager to handle auth.
Uses the django auth context manager to fill the context.
Alters the attribute user if the user is not authenticated.
"""
# Call the django standard auth function, like 'super()'
context = _auth(request)
# Change the django anonymous user with our anonymous user if anonymous auth
# is enabled
if config['general_system_enable_anonymous'] and isinstance(context['user'], DjangoAnonymousUser):
context['user'] = AnonymousUser()
return context