Merge pull request #2909 from ostcar/rework_auth

Created a function to convert anything possible to a user-collection-element or None
This commit is contained in:
Emanuel Schütze 2017-01-26 21:42:40 +01:00 committed by GitHub
commit 8234340a0c
21 changed files with 209 additions and 332 deletions

View File

@ -102,6 +102,7 @@ Other:
- Accelerated startup process (send all data to the client after login). - Accelerated startup process (send all data to the client after login).
- Added function utils.auth.anonymous_is_enabled which returns true, if it is. - Added function utils.auth.anonymous_is_enabled which returns true, if it is.
- Changed has_perm to support an user id or None (for anyonmous) as first argument. - Changed has_perm to support an user id or None (for anyonmous) as first argument.
- Removed our AnonymousUser. Make sure not to use user.has_perm() anymore.
Version 2.0 (2016-04-18) Version 2.0 (2016-04-18)

View File

@ -1,6 +1,7 @@
from collections import defaultdict from collections import defaultdict
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import AnonymousUser
from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models, transaction from django.db import models, transaction
@ -14,7 +15,6 @@ from openslides.utils.exceptions import OpenSlidesError
from openslides.utils.models import RESTModelMixin from openslides.utils.models import RESTModelMixin
from openslides.utils.utils import to_roman from openslides.utils.utils import to_roman
from ..utils.auth import DjangoAnonymousUser
from .access_permissions import ItemAccessPermissions from .access_permissions import ItemAccessPermissions
@ -340,7 +340,7 @@ class SpeakerManager(models.Manager):
if self.filter(user=user, item=item, begin_time=None).exists(): if self.filter(user=user, item=item, begin_time=None).exists():
raise OpenSlidesError( raise OpenSlidesError(
_('{user} is already on the list of speakers.').format(user=user)) _('{user} is already on the list of speakers.').format(user=user))
if isinstance(user, DjangoAnonymousUser): if isinstance(user, AnonymousUser):
raise OpenSlidesError( raise OpenSlidesError(
_('An anonymous user can not be on lists of speakers.')) _('An anonymous user can not be on lists of speakers.'))
weight = (self.filter(item=item).aggregate( weight = (self.filter(item=item).aggregate(

View File

@ -16,6 +16,7 @@ from openslides.utils.rest_api import (
list_route, list_route,
) )
from ..utils.auth import has_perm
from .access_permissions import ItemAccessPermissions from .access_permissions import ItemAccessPermissions
from .models import Item, Speaker from .models import Item, Speaker
@ -39,16 +40,16 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action in ('metadata', 'manage_speaker', 'tree'): elif self.action in ('metadata', 'manage_speaker', 'tree'):
result = self.request.user.has_perm('agenda.can_see') result = has_perm(self.request.user, 'agenda.can_see')
# For manage_speaker and tree requests the rest of the check is # For manage_speaker and tree requests the rest of the check is
# done in the specific method. See below. # done in the specific method. See below.
elif self.action in ('partial_update', 'update'): elif self.action in ('partial_update', 'update'):
result = (self.request.user.has_perm('agenda.can_see') and result = (has_perm(self.request.user, 'agenda.can_see') and
self.request.user.has_perm('agenda.can_see_hidden_items') and has_perm(self.request.user, 'agenda.can_see_hidden_items') and
self.request.user.has_perm('agenda.can_manage')) has_perm(self.request.user, 'agenda.can_manage'))
elif self.action in ('speak', 'sort_speakers', 'numbering'): elif self.action in ('speak', 'sort_speakers', 'numbering'):
result = (self.request.user.has_perm('agenda.can_see') and result = (has_perm(self.request.user, 'agenda.can_see') and
self.request.user.has_perm('agenda.can_manage')) has_perm(self.request.user, 'agenda.can_manage'))
else: else:
result = False result = False
return result return result
@ -80,14 +81,14 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV
# Check permissions and other conditions. Get user instance. # Check permissions and other conditions. Get user instance.
if user_id is None: if user_id is None:
# Add oneself # Add oneself
if not self.request.user.has_perm('agenda.can_be_speaker'): if not has_perm(self.request.user, 'agenda.can_be_speaker'):
self.permission_denied(request) self.permission_denied(request)
if item.speaker_list_closed: if item.speaker_list_closed:
raise ValidationError({'detail': _('The list of speakers is closed.')}) raise ValidationError({'detail': _('The list of speakers is closed.')})
user = self.request.user user = self.request.user
else: else:
# Add someone else. # Add someone else.
if not self.request.user.has_perm('agenda.can_manage'): if not has_perm(self.request.user, 'agenda.can_manage'):
self.permission_denied(request) self.permission_denied(request)
try: try:
user = get_user_model().objects.get(pk=int(user_id)) user = get_user_model().objects.get(pk=int(user_id))
@ -123,7 +124,7 @@ class ItemViewSet(ListModelMixin, RetrieveModelMixin, UpdateModelMixin, GenericV
message = _('You are successfully removed from the list of speakers.') message = _('You are successfully removed from the list of speakers.')
else: else:
# Remove someone else. # Remove someone else.
if not self.request.user.has_perm('agenda.can_manage'): if not has_perm(self.request.user, 'agenda.can_manage'):
self.permission_denied(request) self.permission_denied(request)
if type(speaker_ids) is int: if type(speaker_ids) is int:
speaker_ids = [speaker_ids] speaker_ids = [speaker_ids]

View File

@ -13,6 +13,7 @@ from openslides.utils.rest_api import (
detail_route, detail_route,
) )
from ..utils.auth import has_perm
from .access_permissions import AssignmentAccessPermissions from .access_permissions import AssignmentAccessPermissions
from .models import Assignment, AssignmentPoll, AssignmentRelatedUser from .models import Assignment, AssignmentPoll, AssignmentRelatedUser
from .serializers import AssignmentAllPollSerializer from .serializers import AssignmentAllPollSerializer
@ -42,14 +43,14 @@ class AssignmentViewSet(ModelViewSet):
result = True result = True
elif self.action in ('create', 'partial_update', 'update', 'destroy', elif self.action in ('create', 'partial_update', 'update', 'destroy',
'mark_elected', 'create_poll', 'sort_related_users'): 'mark_elected', 'create_poll', 'sort_related_users'):
result = (self.request.user.has_perm('assignments.can_see') and result = (has_perm(self.request.user, 'assignments.can_see') and
self.request.user.has_perm('assignments.can_manage')) has_perm(self.request.user, 'assignments.can_manage'))
elif self.action == 'candidature_self': elif self.action == 'candidature_self':
result = (self.request.user.has_perm('assignments.can_see') and result = (has_perm(self.request.user, 'assignments.can_see') and
self.request.user.has_perm('assignments.can_nominate_self')) has_perm(self.request.user, 'assignments.can_nominate_self'))
elif self.action == 'candidature_other': elif self.action == 'candidature_other':
result = (self.request.user.has_perm('assignments.can_see') and result = (has_perm(self.request.user, 'assignments.can_see') and
self.request.user.has_perm('assignments.can_nominate_other')) has_perm(self.request.user, 'assignments.can_nominate_other'))
else: else:
result = False result = False
return result return result
@ -73,7 +74,7 @@ class AssignmentViewSet(ModelViewSet):
def nominate_self(self, request, assignment): def nominate_self(self, request, assignment):
if assignment.phase == assignment.PHASE_FINISHED: if assignment.phase == assignment.PHASE_FINISHED:
raise ValidationError({'detail': _('You can not candidate to this election because it is finished.')}) raise ValidationError({'detail': _('You can not candidate to this election because it is finished.')})
if assignment.phase == assignment.PHASE_VOTING and not request.user.has_perm('assignments.can_manage'): if assignment.phase == assignment.PHASE_VOTING and not has_perm(request.user, 'assignments.can_manage'):
# To nominate self during voting you have to be a manager. # To nominate self during voting you have to be a manager.
self.permission_denied(request) self.permission_denied(request)
# If the request.user is already a candidate he can nominate himself nevertheless. # If the request.user is already a candidate he can nominate himself nevertheless.
@ -84,7 +85,7 @@ class AssignmentViewSet(ModelViewSet):
# Withdraw candidature. # Withdraw candidature.
if assignment.phase == assignment.PHASE_FINISHED: if assignment.phase == assignment.PHASE_FINISHED:
raise ValidationError({'detail': _('You can not withdraw your candidature to this election because it is finished.')}) raise ValidationError({'detail': _('You can not withdraw your candidature to this election because it is finished.')})
if assignment.phase == assignment.PHASE_VOTING and not request.user.has_perm('assignments.can_manage'): if assignment.phase == assignment.PHASE_VOTING and not has_perm(request.user, 'assignments.can_manage'):
# To withdraw self during voting you have to be a manager. # To withdraw self during voting you have to be a manager.
self.permission_denied(request) self.permission_denied(request)
if not assignment.is_candidate(request.user): if not assignment.is_candidate(request.user):
@ -133,7 +134,7 @@ class AssignmentViewSet(ModelViewSet):
if assignment.phase == assignment.PHASE_FINISHED: if assignment.phase == assignment.PHASE_FINISHED:
detail = _('You can not nominate someone to this election because it is finished.') detail = _('You can not nominate someone to this election because it is finished.')
raise ValidationError({'detail': detail}) raise ValidationError({'detail': detail})
if assignment.phase == assignment.PHASE_VOTING and not request.user.has_perm('assignments.can_manage'): if assignment.phase == assignment.PHASE_VOTING and not has_perm(request.user, 'assignments.can_manage'):
# To nominate another user during voting you have to be a manager. # To nominate another user during voting you have to be a manager.
self.permission_denied(request) self.permission_denied(request)
if assignment.is_candidate(user): if assignment.is_candidate(user):
@ -143,7 +144,7 @@ class AssignmentViewSet(ModelViewSet):
def delete_other(self, request, user, assignment): def delete_other(self, request, user, assignment):
# To delete candidature status you have to be a manager. # To delete candidature status you have to be a manager.
if not request.user.has_perm('assignments.can_manage'): if not has_perm(request.user, 'assignments.can_manage'):
self.permission_denied(request) self.permission_denied(request)
if assignment.phase == assignment.PHASE_FINISHED: if assignment.phase == assignment.PHASE_FINISHED:
detail = _("You can not delete someone's candidature to this election because it is finished.") detail = _("You can not delete someone's candidature to this election because it is finished.")
@ -243,5 +244,5 @@ class AssignmentPollViewSet(UpdateModelMixin, DestroyModelMixin, GenericViewSet)
""" """
Returns True if the user has required permissions. Returns True if the user has required permissions.
""" """
return (self.request.user.has_perm('assignments.can_see') and return (has_perm(self.request.user, 'assignments.can_see') and
self.request.user.has_perm('assignments.can_manage')) has_perm(self.request.user, 'assignments.can_manage'))

View File

@ -1,5 +1,7 @@
from django.contrib.auth.models import AnonymousUser
from ..utils.access_permissions import BaseAccessPermissions from ..utils.access_permissions import BaseAccessPermissions
from ..utils.auth import DjangoAnonymousUser, anonymous_is_enabled, has_perm from ..utils.auth import anonymous_is_enabled, has_perm
class ProjectorAccessPermissions(BaseAccessPermissions): class ProjectorAccessPermissions(BaseAccessPermissions):
@ -31,7 +33,7 @@ class TagAccessPermissions(BaseAccessPermissions):
""" """
# Every authenticated user can retrieve tags. Anonymous users can do # Every authenticated user can retrieve tags. Anonymous users can do
# so if they are enabled. # so if they are enabled.
return not isinstance(user, DjangoAnonymousUser) or anonymous_is_enabled() return not isinstance(user, AnonymousUser) or anonymous_is_enabled()
def get_serializer_class(self, user=None): def get_serializer_class(self, user=None):
""" """
@ -112,7 +114,7 @@ class ConfigAccessPermissions(BaseAccessPermissions):
""" """
# Every authenticated user can see the metadata and list or retrieve # Every authenticated user can see the metadata and list or retrieve
# the config. Anonymous users can do so if they are enabled. # the config. Anonymous users can do so if they are enabled.
return not isinstance(user, DjangoAnonymousUser) or anonymous_is_enabled() return not isinstance(user, AnonymousUser) or anonymous_is_enabled()
def get_full_data(self, instance): def get_full_data(self, instance):
""" """

View File

@ -17,7 +17,7 @@ from django.utils.translation import ugettext as _
from .. import __version__ as version from .. import __version__ as version
from ..utils import views as utils_views from ..utils import views as utils_views
from ..utils.auth import anonymous_is_enabled from ..utils.auth import anonymous_is_enabled, has_perm
from ..utils.autoupdate import inform_changed_data, inform_deleted_data from ..utils.autoupdate import inform_changed_data, inform_deleted_data
from ..utils.collection import Collection, CollectionElement from ..utils.collection import Collection, CollectionElement
from ..utils.plugins import ( from ..utils.plugins import (
@ -213,15 +213,15 @@ class ProjectorViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action == 'metadata': elif self.action == 'metadata':
result = self.request.user.has_perm('core.can_see_projector') result = has_perm(self.request.user, 'core.can_see_projector')
elif self.action in ( elif self.action in (
'create', 'update', 'partial_update', 'destroy', 'create', 'update', 'partial_update', 'destroy',
'activate_elements', 'prune_elements', 'update_elements', 'deactivate_elements', 'clear_elements', 'activate_elements', 'prune_elements', 'update_elements', 'deactivate_elements', 'clear_elements',
'control_view', 'set_resolution', 'set_scroll', 'control_blank', 'broadcast', 'control_view', 'set_resolution', 'set_scroll', 'control_blank', 'broadcast',
'set_projectiondefault', 'set_projectiondefault',
): ):
result = (self.request.user.has_perm('core.can_see_projector') and result = (has_perm(self.request.user, 'core.can_see_projector') and
self.request.user.has_perm('core.can_manage_projector')) has_perm(self.request.user, 'core.can_manage_projector'))
else: else:
result = False result = False
return result return result
@ -576,7 +576,7 @@ class TagViewSet(ModelViewSet):
# Anonymous users can do so if they are enabled. # Anonymous users can do so if they are enabled.
result = self.request.user.is_authenticated() or anonymous_is_enabled() result = self.request.user.is_authenticated() or anonymous_is_enabled()
elif self.action in ('create', 'update', 'destroy'): elif self.action in ('create', 'update', 'destroy'):
result = self.request.user.has_perm('core.can_manage_tags') result = has_perm(self.request.user, 'core.can_manage_tags')
else: else:
result = False result = False
return result return result
@ -633,7 +633,7 @@ class ConfigViewSet(ViewSet):
# enabled. # enabled.
result = self.request.user.is_authenticated() or anonymous_is_enabled() result = self.request.user.is_authenticated() or anonymous_is_enabled()
elif self.action == 'update': elif self.action == 'update':
result = self.request.user.has_perm('core.can_manage_config') result = has_perm(self.request.user, 'core.can_manage_config')
else: else:
result = False result = False
return result return result
@ -705,11 +705,11 @@ class ChatMessageViewSet(ModelViewSet):
# group has the permission core.can_use_chat. # group has the permission core.can_use_chat.
result = ( result = (
self.request.user.is_authenticated() and self.request.user.is_authenticated() and
self.request.user.has_perm('core.can_use_chat')) has_perm(self.request.user, 'core.can_use_chat'))
elif self.action == 'clear': elif self.action == 'clear':
result = ( result = (
self.request.user.has_perm('core.can_use_chat') and has_perm(self.request.user, 'core.can_use_chat') and
self.request.user.has_perm('core.can_manage_chat')) has_perm(self.request.user, 'core.can_manage_chat'))
else: else:
result = False result = False
return result return result
@ -754,7 +754,7 @@ class ProjectorMessageViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action in ('create', 'update', 'destroy'): elif self.action in ('create', 'update', 'destroy'):
result = self.request.user.has_perm('core.can_manage_projector') result = has_perm(self.request.user, 'core.can_manage_projector')
else: else:
result = False result = False
return result return result
@ -776,7 +776,7 @@ class CountdownViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action in ('create', 'update', 'destroy'): elif self.action in ('create', 'update', 'destroy'):
result = self.request.user.has_perm('core.can_manage_projector') result = has_perm(self.request.user, 'core.can_manage_projector')
else: else:
result = False result = False
return result return result

View File

@ -93,10 +93,6 @@ STATICFILES_DIRS = [
AUTH_USER_MODEL = 'users.User' AUTH_USER_MODEL = 'users.User'
AUTHENTICATION_BACKENDS = [
'openslides.utils.auth.CustomizedModelBackend',
]
SESSION_COOKIE_NAME = 'OpenSlidesSessionID' SESSION_COOKIE_NAME = 'OpenSlidesSessionID'
SESSION_EXPIRE_AT_BROWSER_CLOSE = True SESSION_EXPIRE_AT_BROWSER_CLOSE = True
@ -135,17 +131,6 @@ CACHES = {
} }
# Django REST framework
# http://www.django-rest-framework.org/api-guide/settings/
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'openslides.utils.auth.RESTFrameworkAnonymousAuthentication',
)
}
# Django Channels # Django Channels
# http://channels.readthedocs.io/en/latest/ # http://channels.readthedocs.io/en/latest/

View File

@ -1,3 +1,4 @@
from ..utils.auth import has_perm
from ..utils.rest_api import ModelViewSet, ValidationError from ..utils.rest_api import ModelViewSet, ValidationError
from .access_permissions import MediafileAccessPermissions from .access_permissions import MediafileAccessPermissions
from .models import Mediafile from .models import Mediafile
@ -22,17 +23,17 @@ class MediafileViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action == 'metadata': elif self.action == 'metadata':
result = self.request.user.has_perm('mediafiles.can_see') result = has_perm(self.request.user, 'mediafiles.can_see')
elif self.action == 'create': elif self.action == 'create':
result = (self.request.user.has_perm('mediafiles.can_see') and result = (has_perm(self.request.user, 'mediafiles.can_see') and
self.request.user.has_perm('mediafiles.can_upload')) has_perm(self.request.user, 'mediafiles.can_upload'))
elif self.action in ('partial_update', 'update'): elif self.action in ('partial_update', 'update'):
result = (self.request.user.has_perm('mediafiles.can_see') and result = (has_perm(self.request.user, 'mediafiles.can_see') and
self.request.user.has_perm('mediafiles.can_upload') and has_perm(self.request.user, 'mediafiles.can_upload') and
self.request.user.has_perm('mediafiles.can_manage')) has_perm(self.request.user, 'mediafiles.can_manage'))
elif self.action == 'destroy': elif self.action == 'destroy':
result = (self.request.user.has_perm('mediafiles.can_see') and result = (has_perm(self.request.user, 'mediafiles.can_see') and
self.request.user.has_perm('mediafiles.can_manage')) has_perm(self.request.user, 'mediafiles.can_manage'))
else: else:
result = False result = False
return result return result
@ -44,7 +45,7 @@ class MediafileViewSet(ModelViewSet):
# Check permission to check if the uploader has to be changed. # Check permission to check if the uploader has to be changed.
uploader_id = self.request.data.get('uploader_id') uploader_id = self.request.data.get('uploader_id')
if (uploader_id and if (uploader_id and
not request.user.has_perm('mediafiles.can_manage') and not has_perm(request.user, 'mediafiles.can_manage') and
str(self.request.user.pk) != str(uploader_id)): str(self.request.user.pk) != str(uploader_id)):
self.permission_denied(request) self.permission_denied(request)
if not self.request.data.get('mediafile'): if not self.request.data.get('mediafile'):

View File

@ -9,6 +9,7 @@ from django.utils.translation import ugettext_noop
from rest_framework import status from rest_framework import status
from ..core.config import config from ..core.config import config
from ..utils.auth import has_perm
from ..utils.autoupdate import inform_changed_data from ..utils.autoupdate import inform_changed_data
from ..utils.rest_api import ( from ..utils.rest_api import (
DestroyModelMixin, DestroyModelMixin,
@ -61,20 +62,20 @@ class MotionViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action in ('metadata', 'partial_update', 'update'): elif self.action in ('metadata', 'partial_update', 'update'):
result = self.request.user.has_perm('motions.can_see') result = has_perm(self.request.user, 'motions.can_see')
# For partial_update and update requests the rest of the check is # For partial_update and update requests the rest of the check is
# done in the update method. See below. # done in the update method. See below.
elif self.action == 'create': elif self.action == 'create':
result = (self.request.user.has_perm('motions.can_see') and result = (has_perm(self.request.user, 'motions.can_see') and
self.request.user.has_perm('motions.can_create') and has_perm(self.request.user, 'motions.can_create') and
(not config['motions_stop_submitting'] or (not config['motions_stop_submitting'] or
self.request.user.has_perm('motions.can_manage'))) has_perm(self.request.user, 'motions.can_manage')))
elif self.action in ('destroy', 'manage_version', 'set_state', 'set_recommendation', 'create_poll'): elif self.action in ('destroy', 'manage_version', 'set_state', 'set_recommendation', 'create_poll'):
result = (self.request.user.has_perm('motions.can_see') and result = (has_perm(self.request.user, 'motions.can_see') and
self.request.user.has_perm('motions.can_manage')) has_perm(self.request.user, 'motions.can_manage'))
elif self.action == 'support': elif self.action == 'support':
result = (self.request.user.has_perm('motions.can_see') and result = (has_perm(self.request.user, 'motions.can_see') and
self.request.user.has_perm('motions.can_support')) has_perm(self.request.user, 'motions.can_support'))
else: else:
result = False result = False
return result return result
@ -84,7 +85,7 @@ class MotionViewSet(ModelViewSet):
Customized view endpoint to create a new motion. Customized view endpoint to create a new motion.
""" """
# Check permission to send some data. # Check permission to send some data.
if not request.user.has_perm('motions.can_manage'): if not has_perm(request.user, 'motions.can_manage'):
whitelist = ( whitelist = (
'title', 'title',
'text', 'text',
@ -97,7 +98,7 @@ class MotionViewSet(ModelViewSet):
self.permission_denied(request) self.permission_denied(request)
# Check permission to send comment data. # Check permission to send comment data.
if not request.user.has_perm('motions.can_see_and_manage_comments'): if not has_perm(request.user, 'motions.can_see_and_manage_comments'):
try: try:
# Ignore comments data if user is not allowed to send comments. # Ignore comments data if user is not allowed to send comments.
del request.data['comments'] del request.data['comments']
@ -128,13 +129,13 @@ class MotionViewSet(ModelViewSet):
motion = self.get_object() motion = self.get_object()
# Check permissions. # Check permissions.
if (not request.user.has_perm('motions.can_manage') and if (not has_perm(request.user, 'motions.can_manage') and
not (motion.is_submitter(request.user) and not (motion.is_submitter(request.user) and
motion.state.allow_submitter_edit)): motion.state.allow_submitter_edit)):
self.permission_denied(request) self.permission_denied(request)
# Check permission to send only some data. # Check permission to send only some data.
if not request.user.has_perm('motions.can_manage'): if not has_perm(request.user, 'motions.can_manage'):
whitelist = ( whitelist = (
'title', 'title',
'text', 'text',
@ -144,7 +145,7 @@ class MotionViewSet(ModelViewSet):
if key not in whitelist: if key not in whitelist:
# Non-staff users are allowed to send only some data. Ignore other data. # Non-staff users are allowed to send only some data. Ignore other data.
del request.data[key] del request.data[key]
if not request.user.has_perm('motions.can_see_and_manage_comments'): if not has_perm(request.user, 'motions.can_see_and_manage_comments'):
try: try:
del request.data['comments'] del request.data['comments']
except KeyError: except KeyError:
@ -163,7 +164,7 @@ class MotionViewSet(ModelViewSet):
# TODO: Log if a version was updated. # TODO: Log if a version was updated.
updated_motion.write_log([ugettext_noop('Motion updated')], request.user) updated_motion.write_log([ugettext_noop('Motion updated')], request.user)
if (config['motions_remove_supporters'] and updated_motion.state.allow_support and if (config['motions_remove_supporters'] and updated_motion.state.allow_support and
not request.user.has_perm('motions.can_manage')): not has_perm(request.user, 'motions.can_manage')):
updated_motion.supporters.clear() updated_motion.supporters.clear()
updated_motion.write_log([ugettext_noop('All supporters removed')], request.user) updated_motion.write_log([ugettext_noop('All supporters removed')], request.user)
return Response(serializer.data) return Response(serializer.data)
@ -352,8 +353,8 @@ class MotionPollViewSet(UpdateModelMixin, DestroyModelMixin, GenericViewSet):
""" """
Returns True if the user has required permissions. Returns True if the user has required permissions.
""" """
return (self.request.user.has_perm('motions.can_see') and return (has_perm(self.request.user, 'motions.can_see') and
self.request.user.has_perm('motions.can_manage')) has_perm(self.request.user, 'motions.can_manage'))
class MotionChangeRecommendationViewSet(ModelViewSet): class MotionChangeRecommendationViewSet(ModelViewSet):
@ -373,9 +374,9 @@ class MotionChangeRecommendationViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action == 'metadata': elif self.action == 'metadata':
result = self.request.user.has_perm('motions.can_see') result = has_perm(self.request.user, 'motions.can_see')
elif self.action in ('create', 'destroy', 'partial_update', 'update'): elif self.action in ('create', 'destroy', 'partial_update', 'update'):
result = self.request.user.has_perm('motions.can_manage') result = has_perm(self.request.user, 'motions.can_manage')
else: else:
result = False result = False
return result return result
@ -398,10 +399,10 @@ class CategoryViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action == 'metadata': elif self.action == 'metadata':
result = self.request.user.has_perm('motions.can_see') result = has_perm(self.request.user, 'motions.can_see')
elif self.action in ('create', 'partial_update', 'update', 'destroy', 'numbering'): elif self.action in ('create', 'partial_update', 'update', 'destroy', 'numbering'):
result = (self.request.user.has_perm('motions.can_see') and result = (has_perm(self.request.user, 'motions.can_see') and
self.request.user.has_perm('motions.can_manage')) has_perm(self.request.user, 'motions.can_manage'))
else: else:
result = False result = False
return result return result
@ -511,10 +512,10 @@ class MotionBlockViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action == 'metadata': elif self.action == 'metadata':
result = self.request.user.has_perm('motions.can_see') result = has_perm(self.request.user, 'motions.can_see')
elif self.action in ('create', 'partial_update', 'update', 'destroy', 'follow_recommendations'): elif self.action in ('create', 'partial_update', 'update', 'destroy', 'follow_recommendations'):
result = (self.request.user.has_perm('motions.can_see') and result = (has_perm(self.request.user, 'motions.can_see') and
self.request.user.has_perm('motions.can_manage')) has_perm(self.request.user, 'motions.can_manage'))
else: else:
result = False result = False
return result return result
@ -559,10 +560,10 @@ class WorkflowViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action == 'metadata': elif self.action == 'metadata':
result = self.request.user.has_perm('motions.can_see') result = has_perm(self.request.user, 'motions.can_see')
elif self.action in ('create', 'partial_update', 'update', 'destroy'): elif self.action in ('create', 'partial_update', 'update', 'destroy'):
result = (self.request.user.has_perm('motions.can_see') and result = (has_perm(self.request.user, 'motions.can_see') and
self.request.user.has_perm('motions.can_manage')) has_perm(self.request.user, 'motions.can_manage'))
else: else:
result = False result = False
return result return result

View File

@ -1,5 +1,6 @@
from openslides.utils.rest_api import ModelViewSet from openslides.utils.rest_api import ModelViewSet
from ..utils.auth import has_perm
from .access_permissions import TopicAccessPermissions from .access_permissions import TopicAccessPermissions
from .models import Topic from .models import Topic
@ -21,5 +22,5 @@ class TopicViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
else: else:
result = self.request.user.has_perm('agenda.can_manage') result = has_perm(self.request.user, 'agenda.can_manage')
return result return result

View File

@ -1,5 +1,7 @@
from django.contrib.auth.models import AnonymousUser
from ..utils.access_permissions import BaseAccessPermissions from ..utils.access_permissions import BaseAccessPermissions
from ..utils.auth import DjangoAnonymousUser, anonymous_is_enabled, has_perm from ..utils.auth import anonymous_is_enabled, has_perm
class UserAccessPermissions(BaseAccessPermissions): class UserAccessPermissions(BaseAccessPermissions):
@ -42,7 +44,9 @@ class UserAccessPermissions(BaseAccessPermissions):
case = MANY_DATA case = MANY_DATA
else: else:
case = LITTLE_DATA case = LITTLE_DATA
elif user.pk == full_data.get('id'): elif user is not None and user.id == full_data.get('id'):
# An authenticated user without the permission to see users tries
# to see himself.
case = LITTLE_DATA case = LITTLE_DATA
else: else:
case = NO_DATA case = NO_DATA
@ -92,10 +96,7 @@ class GroupAccessPermissions(BaseAccessPermissions):
""" """
# Every authenticated user can retrieve groups. Anonymous users can do # Every authenticated user can retrieve groups. Anonymous users can do
# so if they are enabled. # so if they are enabled.
# Our AnonymousUser is a subclass of the DjangoAnonymousUser. Normaly, a return not isinstance(user, AnonymousUser) or anonymous_is_enabled()
# DjangoAnonymousUser means, that AnonymousUser is disabled. But this is
# no garanty. send_data uses the AnonymousUser in any case.
return not isinstance(user, DjangoAnonymousUser) or anonymous_is_enabled()
def get_serializer_class(self, user=None): def get_serializer_class(self, user=None):
""" """

View File

@ -216,6 +216,12 @@ class User(RESTModelMixin, PermissionsMixin, AbstractBaseUser):
self.structure_level, self.structure_level,
self.about_me)) self.about_me))
def has_perm(self, perm):
"""
This method is closed. Do not use it but use openslides.utils.auth.has_perm.
"""
raise RuntimeError('Do not use user.has_perm() but use openslides.utils.auth.has_perm')
class GroupManager(GroupManager): class GroupManager(GroupManager):
""" """

View File

@ -5,7 +5,7 @@ from django.utils.encoding import force_text
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from ..core.config import config from ..core.config import config
from ..utils.auth import anonymous_is_enabled from ..utils.auth import anonymous_is_enabled, has_perm
from ..utils.collection import CollectionElement from ..utils.collection import CollectionElement
from ..utils.rest_api import ( from ..utils.rest_api import (
ModelViewSet, ModelViewSet,
@ -40,11 +40,11 @@ class UserViewSet(ModelViewSet):
if self.action in ('list', 'retrieve'): if self.action in ('list', 'retrieve'):
result = self.get_access_permissions().check_permissions(self.request.user) result = self.get_access_permissions().check_permissions(self.request.user)
elif self.action in ('metadata', 'update', 'partial_update'): elif self.action in ('metadata', 'update', 'partial_update'):
result = self.request.user.has_perm('users.can_see_name') result = has_perm(self.request.user, 'users.can_see_name')
elif self.action in ('create', 'destroy', 'reset_password'): elif self.action in ('create', 'destroy', 'reset_password'):
result = (self.request.user.has_perm('users.can_see_name') and result = (has_perm(self.request.user, 'users.can_see_name') and
self.request.user.has_perm('users.can_see_extra_data') and has_perm(self.request.user, 'users.can_see_extra_data') and
self.request.user.has_perm('users.can_manage')) has_perm(self.request.user, 'users.can_manage'))
else: else:
result = False result = False
return result return result
@ -59,8 +59,8 @@ class UserViewSet(ModelViewSet):
wants to update himself or is manager. wants to update himself or is manager.
""" """
# Check manager perms # Check manager perms
if (request.user.has_perm('users.can_see_extra_data') and if (has_perm(request.user, 'users.can_see_extra_data') and
request.user.has_perm('users.can_manage')): has_perm(request.user, 'users.can_manage')):
if request.data.get('is_active') is False and self.get_object() == request.user: if request.data.get('is_active') is False and self.get_object() == request.user:
# A user can not deactivate himself. # A user can not deactivate himself.
raise ValidationError({'detail': _('You can not deactivate yourself.')}) raise ValidationError({'detail': _('You can not deactivate yourself.')})
@ -141,9 +141,9 @@ class GroupViewSet(ModelViewSet):
result = self.request.user.is_authenticated() or anonymous_is_enabled() result = self.request.user.is_authenticated() or anonymous_is_enabled()
elif self.action in ('create', 'partial_update', 'update', 'destroy'): elif self.action in ('create', 'partial_update', 'update', 'destroy'):
# Users with all app permissions can edit groups. # Users with all app permissions can edit groups.
result = (self.request.user.has_perm('users.can_see_name') and result = (has_perm(self.request.user, 'users.can_see_name') and
self.request.user.has_perm('users.can_see_extra_data') and has_perm(self.request.user, 'users.can_see_extra_data') and
self.request.user.has_perm('users.can_manage')) has_perm(self.request.user, 'users.can_manage'))
else: else:
# Deny request in any other case. # Deny request in any other case.
result = False result = False

View File

@ -1,150 +1,31 @@
from django.contrib.auth import get_user as _get_user
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend from django.contrib.auth.models import AnonymousUser
from django.contrib.auth.models import AnonymousUser as DjangoAnonymousUser
from django.contrib.auth.models import Permission
from django.utils.functional import SimpleLazyObject
from rest_framework.authentication import BaseAuthentication
from .collection import CollectionElement from .collection import CollectionElement
# Registered users
class CustomizedModelBackend(ModelBackend):
"""
Customized backend for authentication. Ensures that all users
without a group have the permissions of the group 'Default' (pk=1).
See AUTHENTICATION_BACKENDS settings.
"""
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 is minimum requirement. 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:
if user_obj.groups.all().count() == 0: # user is in no group
perms = Permission.objects.filter(group__pk=1) # group 'default' (pk=1)
else:
user_groups_field = get_user_model()._meta.get_field('groups')
user_groups_query = 'group__%s' % user_groups_field.related_query_name()
perms = Permission.objects.filter(**{user_groups_query: user_obj})
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
# Anonymous users
class AnonymousUser(DjangoAnonymousUser):
"""
Class for anonymous user instances which have the permissions from the
group 'Anonymous' (pk=1).
"""
def has_perm(self, perm, obj=None):
"""
Checks if the user has a specific permission.
"""
default_group = CollectionElement.from_values('users/group', 1)
return perm in default_group.get_full_data()['permissions']
class RESTFrameworkAnonymousAuthentication(BaseAuthentication):
"""
Authentication class for the Django REST framework.
Sets the user to the our AnonymousUser but only if
anonymous user is enabled in the config.
"""
def authenticate(self, request):
if anonymous_is_enabled():
return (AnonymousUser(), None)
return None
class AuthenticationMiddleware:
"""
Middleware to get the logged in user in users.
Uses AnonymousUser instead of Django's 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.utils.auth.AuthenticationMiddleware'."
)
request.user = SimpleLazyObject(lambda: get_user(request))
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 anonymous_is_enabled() and isinstance(return_user, DjangoAnonymousUser):
return_user = AnonymousUser()
request._cached_user = return_user
return return_user
def has_perm(user, perm): def has_perm(user, perm):
""" """
Checks that user has a specific permission. Checks that user has a specific permission.
User can be an user object, an user id None (for anonymous) or a User can be a CollectionElement of a user or None.
CollectionElement for a user.
""" """
# First, convert a user id or None to an anonymous user or an CollectionElement group_collection_string = 'users/group' # This is the hard coded collection string for openslides.users.models.Group
if user is None and anonymous_is_enabled():
user = AnonymousUser()
elif user is None:
user = DjangoAnonymousUser()
elif isinstance(user, int):
user = CollectionElement.from_values('users/user', user)
if isinstance(user, AnonymousUser): # Convert user to right type
# Our anonymous user has a has_perm-method that works with the cache user = user_to_collection_user(user)
# system. So we can use it here. if user is None and not anonymous_is_enabled():
has_perm = user.has_perm(perm)
elif isinstance(user, DjangoAnonymousUser):
# The django anonymous user is only used when anonymous user is disabled
# So he never has permissions to see anything.
has_perm = False has_perm = False
elif user is None:
# Use the permissions from the default group with id 1.
default_group = CollectionElement.from_values(group_collection_string, 1)
has_perm = perm in default_group.get_full_data()['permissions']
else: else:
if isinstance(user, get_user_model()):
# Converts a user object to a collection element.
# from_instance can not be used because the user serializer loads
# the group from the db. So each call to from_instance(user) consts
# one db query.
user = CollectionElement.from_values('users/user', user.id)
# Get all groups of the user and then see, if one group has the required # Get all groups of the user and then see, if one group has the required
# permission. If the user has no groups, then use group 1. # permission. If the user has no groups, then use group 1.
group_ids = user.get_full_data()['groups_id'] or [1] group_ids = user.get_full_data()['groups_id'] or [1]
for group_id in group_ids: for group_id in group_ids:
group = CollectionElement.from_values('users/group', group_id) group = CollectionElement.from_values(group_collection_string, group_id)
if perm in group.get_full_data()['permissions']: if perm in group.get_full_data()['permissions']:
has_perm = True has_perm = True
break break
@ -154,5 +35,49 @@ def has_perm(user, perm):
def anonymous_is_enabled(): def anonymous_is_enabled():
from ..core.config import config """
return config['general_system_enable_anonymous'] Returns True if the anonymous user is enabled in the settings.
"""
return (CollectionElement.from_values('core/config', 'general_system_enable_anonymous')
.get_full_data()['value'])
def user_to_collection_user(user):
"""
Takes an object, that represents a user and converts it to a CollectionElement
or to None, if it is an anonymous user.
User can be
* an user object,
* a CollectionElement of an user,
* an user id or
* an anonymous user.
Raises an TypeError, if the given user object can not be converted.
"""
User = get_user_model()
if user is None:
# Nothing to do
pass
elif isinstance(user, CollectionElement) and user.collection_string == User.get_collection_string():
# Nothing to do
pass
elif isinstance(user, CollectionElement):
raise TypeError(
"Unsupported type for user. Only CollectionElements for users can be"
"used. Not {}".format(user.collection_string))
elif isinstance(user, int):
user = CollectionElement.from_values(User.get_collection_string(), user)
elif isinstance(user, AnonymousUser):
user = None
elif isinstance(user, User):
# Converts a user object to a collection element.
# from_instance can not be used because the user serializer loads
# the group from the db. So each call to from_instance(user) costs
# one db query.
user = CollectionElement.from_values(User.get_collection_string(), user.id)
else:
raise TypeError(
"Unsupported type for user. User {} has type {}.".format(user, type(user)))
return user

View File

@ -11,7 +11,7 @@ from django.db import transaction
from ..core.config import config from ..core.config import config
from ..core.models import Projector from ..core.models import Projector
from .auth import AnonymousUser, anonymous_is_enabled from .auth import has_perm, user_to_collection_user
from .cache import websocket_user_cache from .cache import websocket_user_cache
from .collection import Collection, CollectionElement, CollectionElementList from .collection import Collection, CollectionElement, CollectionElementList
@ -67,7 +67,8 @@ def ws_add_site(message):
# Skip apps that do not implement get_startup_elements # Skip apps that do not implement get_startup_elements
continue continue
for collection in get_startup_elements(): for collection in get_startup_elements():
output.extend(collection.as_autoupdate_for_user(message.user.id)) user = user_to_collection_user(message.user.id)
output.extend(collection.as_autoupdate_for_user(user))
# Send all data. If there is no data, then only accept the connection # Send all data. If there is no data, then only accept the connection
if output: if output:
@ -91,12 +92,9 @@ def ws_add_projector(message, projector_id):
Adds the websocket connection to a group specific to the projector with the given id. Adds the websocket connection to a group specific to the projector with the given id.
Also sends all data that are shown on the projector. Also sends all data that are shown on the projector.
""" """
user = message.user user = message.user.id
# user is the django anonymous user. We have our own.
if user.is_anonymous and anonymous_is_enabled():
user = AnonymousUser()
if not user.has_perm('core.can_see_projector'): if not has_perm(user, 'core.can_see_projector'):
send_or_wait(message.reply_channel.send, {'text': 'No permissions to see this projector.'}) send_or_wait(message.reply_channel.send, {'text': 'No permissions to see this projector.'})
else: else:
try: try:
@ -150,7 +148,7 @@ def send_data(message):
for user_id, channel_names in websocket_user_cache.get_all().items(): for user_id, channel_names in websocket_user_cache.get_all().items():
if not user_id: if not user_id:
# Anonymous user # Anonymous user
user = AnonymousUser() user = None
else: else:
user = CollectionElement.from_values('users/user', user_id) user = CollectionElement.from_values('users/user', user_id)
output = collection_elements.as_autoupdate_for_user(user) output = collection_elements.as_autoupdate_for_user(user)

View File

@ -29,6 +29,7 @@ from rest_framework.viewsets import GenericViewSet as _GenericViewSet # noqa
from rest_framework.viewsets import ModelViewSet as _ModelViewSet # noqa from rest_framework.viewsets import ModelViewSet as _ModelViewSet # noqa
from rest_framework.viewsets import ViewSet as _ViewSet # noqa from rest_framework.viewsets import ViewSet as _ViewSet # noqa
from .auth import user_to_collection_user
from .collection import Collection, CollectionElement from .collection import Collection, CollectionElement
router = DefaultRouter() router = DefaultRouter()
@ -182,7 +183,8 @@ class ListModelMixin(_ListModelMixin):
response = super().list(request, *args, **kwargs) response = super().list(request, *args, **kwargs)
else: else:
collection = Collection(collection_string) collection = Collection(collection_string)
response = Response(collection.as_list_for_user(request.user)) user = user_to_collection_user(request.user)
response = Response(collection.as_list_for_user(user))
return response return response
@ -206,8 +208,9 @@ class RetrieveModelMixin(_RetrieveModelMixin):
lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field lookup_url_kwarg = self.lookup_url_kwarg or self.lookup_field
collection_element = CollectionElement.from_values( collection_element = CollectionElement.from_values(
collection_string, self.kwargs[lookup_url_kwarg]) collection_string, self.kwargs[lookup_url_kwarg])
user = user_to_collection_user(request.user)
try: try:
content = collection_element.as_dict_for_user(request.user) content = collection_element.as_dict_for_user(user)
except collection_element.get_model().DoesNotExist: except collection_element.get_model().DoesNotExist:
raise Http404 raise Http404
if content is None: if content is None:

View File

@ -102,14 +102,10 @@ class TestTagDBQueries(TestCase):
def test_anonymous(self): def test_anonymous(self):
""" """
Tests that only the following db queries are done: Tests that only the following db queries are done:
* 2 requests to get the permission for anonymous (config and permissions) * 1 requests to see if anonyomus is enabled
* 2 requests to get the list of all projectors, * 2 requests to get the list of all projectors,
* 10 requests for to config
The last 10 requests are a bug.
""" """
with self.assertNumQueries(14): with self.assertNumQueries(3):
self.client.get(reverse('tag-list')) self.client.get(reverse('tag-list'))
@ -140,14 +136,10 @@ class TestConfigDBQueries(TestCase):
def test_anonymous(self): def test_anonymous(self):
""" """
Tests that only the following db queries are done: Tests that only the following db queries are done:
* 2 requests to get the permission for anonymous (config and permissions), * 1 requests to see if anonymous is enabled
* 1 to get all config value and * 1 to get all config value and
* 57 requests to find out if anonymous is enabled.
TODO: The last 57 requests are a bug.
""" """
with self.assertNumQueries(63): with self.assertNumQueries(2):
self.client.get(reverse('config-list')) self.client.get(reverse('config-list'))

View File

@ -78,18 +78,10 @@ class TestGroupDBQueries(TestCase):
def test_anonymous(self): def test_anonymous(self):
""" """
Tests that only the following db queries are done: Tests that only the following db queries are done:
* 2 requests to find out if anonymous is enabled * 1 requests to find out if anonymous is enabled
* 3 request to get the list of all groups and * 3 request to get the list of all groups and
* 14 Requests to find out if anonymous is enabled.
TODO: There should be only one request to find out if anonymous is enabled.
The reason for the last 14 requests is the base get_restricted_data()
method that is used by the group access_permissions. It calls check_permissions().
But this is important for the autoupdate-case and can only be fixt by
caching the config object.
""" """
with self.assertNumQueries(19): with self.assertNumQueries(4):
self.client.get(reverse('group-list')) self.client.get(reverse('group-list'))

View File

@ -15,24 +15,32 @@ class ItemViewSetManageSpeaker(TestCase):
self.view_instance.get_object = get_object_mock = MagicMock() self.view_instance.get_object = get_object_mock = MagicMock()
get_object_mock.return_value = self.mock_item = MagicMock() get_object_mock.return_value = self.mock_item = MagicMock()
@patch('openslides.agenda.views.has_perm')
@patch('openslides.agenda.views.Speaker') @patch('openslides.agenda.views.Speaker')
def test_add_oneself_as_speaker(self, mock_speaker): def test_add_oneself_as_speaker(self, mock_speaker, mock_has_perm):
self.request.method = 'POST' self.request.method = 'POST'
self.request.user.has_perm.return_value = True self.request.user = 1
mock_has_perm.return_value = True
self.request.data = {} self.request.data = {}
self.mock_item.speaker_list_closed = False self.mock_item.speaker_list_closed = False
self.view_instance.manage_speaker(self.request) self.view_instance.manage_speaker(self.request)
mock_speaker.objects.add.assert_called_with(self.request.user, self.mock_item) mock_speaker.objects.add.assert_called_with(self.request.user, self.mock_item)
@patch('openslides.agenda.views.has_perm')
@patch('openslides.agenda.views.get_user_model') @patch('openslides.agenda.views.get_user_model')
@patch('openslides.agenda.views.Speaker') @patch('openslides.agenda.views.Speaker')
def test_add_someone_else_as_speaker(self, mock_speaker, mock_get_user_model): def test_add_someone_else_as_speaker(self, mock_speaker, mock_get_user_model, mock_has_perm):
self.request.method = 'POST' self.request.method = 'POST'
self.request.user.has_perm.return_value = True self.request.user = 1
self.request.data = {'user': '2'} # It is assumed that the request user has pk!=2. self.request.data = {'user': '2'} # It is assumed that the request user has pk!=2.
mock_get_user_model.return_value = MockUser = MagicMock() mock_get_user_model.return_value = MockUser = MagicMock()
MockUser.objects.get.return_value = mock_user = MagicMock() MockUser.objects.get.return_value = mock_user = MagicMock()
mock_has_perm.return_value = True
self.view_instance.manage_speaker(self.request) self.view_instance.manage_speaker(self.request)
MockUser.objects.get.assert_called_with(pk=2) MockUser.objects.get.assert_called_with(pk=2)
mock_speaker.objects.add.assert_called_with(mock_user, self.mock_item) mock_speaker.objects.add.assert_called_with(mock_user, self.mock_item)
@ -44,12 +52,16 @@ class ItemViewSetManageSpeaker(TestCase):
mock_queryset = mock_speaker.objects.filter.return_value.exclude.return_value mock_queryset = mock_speaker.objects.filter.return_value.exclude.return_value
mock_queryset.get.return_value.delete.assert_called_with() mock_queryset.get.return_value.delete.assert_called_with()
@patch('openslides.agenda.views.has_perm')
@patch('openslides.agenda.views.Speaker') @patch('openslides.agenda.views.Speaker')
def test_remove_someone_else(self, mock_speaker): def test_remove_someone_else(self, mock_speaker, mock_has_perm):
self.request.method = 'DELETE' self.request.method = 'DELETE'
self.request.user.has_perm.return_value = True self.request.user = 1
self.request.data = {'speaker': '1'} self.request.data = {'speaker': '1'}
mock_has_perm.return_value = True
self.view_instance.manage_speaker(self.request) self.view_instance.manage_speaker(self.request)
mock_speaker.objects.get.assert_called_with(pk=1) mock_speaker.objects.get.assert_called_with(pk=1)
mock_speaker.objects.get.return_value.delete.assert_called_with() mock_speaker.objects.get.return_value.delete.assert_called_with()

View File

@ -16,10 +16,14 @@ class MotionViewSetCreate(TestCase):
self.view_instance.get_serializer = get_serializer_mock = MagicMock() self.view_instance.get_serializer = get_serializer_mock = MagicMock()
get_serializer_mock.return_value = self.mock_serializer = MagicMock() get_serializer_mock.return_value = self.mock_serializer = MagicMock()
@patch('openslides.motions.views.has_perm')
@patch('openslides.motions.views.config') @patch('openslides.motions.views.config')
def test_simple_create(self, mock_config): def test_simple_create(self, mock_config, mock_has_perm):
self.request.user.has_perm.return_value = True self.request.user = 1
mock_has_perm.return_value = True
self.view_instance.create(self.request) self.view_instance.create(self.request)
self.mock_serializer.save.assert_called_with(request_user=self.request.user) self.mock_serializer.save.assert_called_with(request_user=self.request.user)
@ -36,11 +40,15 @@ class MotionViewSetUpdate(TestCase):
self.view_instance.get_serializer = get_serializer_mock = MagicMock() self.view_instance.get_serializer = get_serializer_mock = MagicMock()
get_serializer_mock.return_value = self.mock_serializer = MagicMock() get_serializer_mock.return_value = self.mock_serializer = MagicMock()
@patch('openslides.motions.views.has_perm')
@patch('openslides.motions.views.config') @patch('openslides.motions.views.config')
def test_simple_update(self, mock_config): def test_simple_update(self, mock_config, mock_has_perm):
self.request.user.has_perm.return_value = True self.request.user = 1
self.request.data.get.return_value = versioning_mock = MagicMock() self.request.data.get.return_value = versioning_mock = MagicMock()
mock_has_perm.return_value = True
self.view_instance.update(self.request) self.view_instance.update(self.request)
self.mock_serializer.save.assert_called_with(disable_versioning=versioning_mock) self.mock_serializer.save.assert_called_with(disable_versioning=versioning_mock)

View File

@ -1,53 +0,0 @@
from unittest import TestCase, skip
from unittest.mock import MagicMock, patch
from openslides.utils.auth import AnonymousUser, get_user
@skip # I don't know how to patch the config if it is not imported in the global space
@patch('openslides.utils.auth.config')
@patch('openslides.utils.auth._get_user')
class TestGetUser(TestCase):
def test_not_in_cache(self, mock_get_user, mock_config):
mock_config.__getitem__.return_value = True
mock_get_user.return_value = AnonymousUser()
request = MagicMock()
del request._cached_user
user = get_user(request)
mock_get_user.assert_called_once_with(request)
self.assertEqual(user, AnonymousUser())
self.assertEqual(request._cached_user, AnonymousUser())
def test_in_cache(self, mock_get_user, mock_config):
request = MagicMock()
request._cached_user = 'my_user'
user = get_user(request)
self.assertFalse(
mock_get_user.called,
"_get_user should not have been called when the user object is in cache")
self.assertEqual(
user,
'my_user',
"The user in cache should be returned")
def test_disabled_anonymous_user(self, mock_get_user, mock_config):
mock_config.__getitem__.return_value = False
mock_get_user.return_value = 'django_anonymous_user'
request = MagicMock()
del request._cached_user
user = get_user(request)
mock_get_user.assert_called_once_with(request)
self.assertEqual(
user,
'django_anonymous_user',
"The django user should be returned")
self.assertEqual(
request._cached_user,
'django_anonymous_user',
"The django user should be cached")