From 3b73a4111ea4871f35f30bf3fd833fcdca8058ec Mon Sep 17 00:00:00 2001 From: Lucas Brandstaetter <lucas@brandstaetter.tech> Date: Tue, 10 Dec 2024 18:25:37 +0100 Subject: [PATCH] Add teams authentication backend This backend will allow us to authenticate users based on the teams they are part of. It is based on the default ModelBackend. --- src/backoffice/views/auth.py | 1 + src/backoffice/views/moderation/users.py | 3 ++- src/core/backends.py | 18 ++++++++++++++++++ src/hub/settings/base.py | 3 ++- src/plainui/views/ticket_tokens.py | 3 ++- 5 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 src/core/backends.py diff --git a/src/backoffice/views/auth.py b/src/backoffice/views/auth.py index 5e0e8ff63..89832a316 100644 --- a/src/backoffice/views/auth.py +++ b/src/backoffice/views/auth.py @@ -48,6 +48,7 @@ class AuthDebugView(ConferenceLoginRequiredMixin, View): 'active': u.is_active, 'flags': [], 'groups': list(u.groups.values_list('name', flat=True)), + 'teams': [f"{x['team__conference__name']}: {x['team__name']}" for x in u.teams.values('team__name', 'team__conference__name')], 'permissions': [str(x) for x in u.get_all_permissions()], } if u.is_superuser: diff --git a/src/backoffice/views/moderation/users.py b/src/backoffice/views/moderation/users.py index d4580d09a..a2816f6c0 100644 --- a/src/backoffice/views/moderation/users.py +++ b/src/backoffice/views/moderation/users.py @@ -2,6 +2,7 @@ import logging from oauth2_provider.models import AccessToken +from django.conf import settings from django.contrib import messages from django.contrib.sessions.exceptions import SuspiciousSession from django.contrib.sessions.models import Session @@ -58,7 +59,7 @@ class ModerationUserDetailView(ModerationAdminMixin, DetailView): for session in Session.objects.all(): try: session_data = session.get_decoded() - if session_data.get('_auth_user_id') == str(user.pk) and session_data.get('_auth_user_backend') == 'django.contrib.auth.backends.ModelBackend': + if session_data.get('_auth_user_id') == str(user.pk) and session_data.get('_auth_user_backend') == settings.BASE_AUTHENTICATION_BACKEND: session.delete() deleted_sessions += 1 diff --git a/src/core/backends.py b/src/core/backends.py new file mode 100644 index 000000000..c5472ee02 --- /dev/null +++ b/src/core/backends.py @@ -0,0 +1,18 @@ +from django.contrib.auth import get_user_model +from django.contrib.auth.backends import ModelBackend +from django.contrib.auth.models import Permission +from django.db.models import Q + +UserModel = get_user_model() + + +class TeamsBackend(ModelBackend): + """ + Authenticates against settings.AUTH_USER_MODEL. + """ + + def _get_group_permissions(self, user_obj): + user_groups_field = get_user_model()._meta.get_field('groups') + user_groups_query = f'group__{user_groups_field.related_query_name()}' + teams = user_obj.teams.values('team') + return Permission.objects.filter(Q(**{user_groups_query: user_obj}) | Q(group__in=teams)) diff --git a/src/hub/settings/base.py b/src/hub/settings/base.py index 087ef7e96..cfffd0307 100644 --- a/src/hub/settings/base.py +++ b/src/hub/settings/base.py @@ -270,10 +270,11 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] +BASE_AUTHENTICATION_BACKEND = 'core.backends.TeamsBackend' AUTHENTICATION_BACKENDS = ( 'rules.permissions.ObjectPermissionBackend', 'oauth2_provider.backends.OAuth2Backend', - 'django.contrib.auth.backends.ModelBackend', + BASE_AUTHENTICATION_BACKEND, ) # Session Cookie configuration diff --git a/src/plainui/views/ticket_tokens.py b/src/plainui/views/ticket_tokens.py index 648c02d5b..ee824d9b5 100644 --- a/src/plainui/views/ticket_tokens.py +++ b/src/plainui/views/ticket_tokens.py @@ -7,6 +7,7 @@ __all__ = ( from django_ratelimit.decorators import ratelimit +from django.conf import settings from django.contrib import messages from django.contrib.auth import login from django.contrib.auth import views as auth_views @@ -143,7 +144,7 @@ class RedeemTokenUserCreateView(ConferenceRequiredMixin, FormView): user = form.save() ConferenceMemberTicket.redeem_pretix_ticket(self.conf, user, form.cleaned_data['token']) ConferenceMember.objects.update_or_create(conference=self.conf, user=user, defaults={'has_ticket': True}) - login(self.request, user, backend='django.contrib.auth.backends.ModelBackend') + login(self.request, user, backend=settings.BASE_AUTHENTICATION_BACKEND) return HttpResponseRedirect(self.get_success_url()) except TicketValidationError as e: form.add_error(None, str(e)) -- GitLab