diff --git a/src/pretix/control/middleware.py b/src/pretix/control/middleware.py index 7cdcda66cd..239fe31e77 100644 --- a/src/pretix/control/middleware.py +++ b/src/pretix/control/middleware.py @@ -43,7 +43,6 @@ from django.urls import get_script_prefix, resolve, reverse from django.utils.encoding import force_str from django.utils.translation import gettext as _ from django_scopes import scope -from hijack.templatetags.hijack_tags import is_hijacked from pretix.base.models import Event, Organizer from pretix.base.models.auth import SuperuserPermissionSet, User @@ -183,7 +182,7 @@ class AuditLogMiddleware: def __call__(self, request): if request.path.startswith(get_script_prefix() + 'control') and request.user.is_authenticated: - if is_hijacked(request): + if getattr(request.user, "is_hijacked", False): hijack_history = request.session.get('hijack_history', False) hijacker = get_object_or_404(User, pk=hijack_history[0]) ss = hijacker.get_active_staff_session(request.session.get('hijacker_session')) diff --git a/src/pretix/control/templates/pretixcontrol/auth/base.html b/src/pretix/control/templates/pretixcontrol/auth/base.html index 727a55f048..bcf23c5fab 100644 --- a/src/pretix/control/templates/pretixcontrol/auth/base.html +++ b/src/pretix/control/templates/pretixcontrol/auth/base.html @@ -1,6 +1,5 @@ {% load compress %} {% load i18n %} -{% load hijack_tags %} {% load static %} @@ -39,7 +38,7 @@ {% endfor %} {% endif %} - {% if request|is_hijacked %} + {% if request.user.is_hijacked %}
{% blocktrans with user=request.user%}You are currently working on behalf of {{ user }}.{% endblocktrans %} diff --git a/src/pretix/control/templates/pretixcontrol/base.html b/src/pretix/control/templates/pretixcontrol/base.html index d0b1f621e2..94b98d3d20 100644 --- a/src/pretix/control/templates/pretixcontrol/base.html +++ b/src/pretix/control/templates/pretixcontrol/base.html @@ -1,7 +1,6 @@ {% load compress %} {% load static %} {% load i18n %} -{% load hijack_tags %} {% load statici18n %} {% load eventsignal %} {% load eventurl %} @@ -351,7 +350,7 @@
{% endif %} - {% if request|is_hijacked %} + {% if request.user.is_hijacked %}
{% blocktrans with user=request.user%}You are currently working on behalf of {{ user }}.{% endblocktrans %} diff --git a/src/pretix/control/views/users.py b/src/pretix/control/views/users.py index 2827934111..33e065c6ee 100644 --- a/src/pretix/control/views/users.py +++ b/src/pretix/control/views/users.py @@ -20,9 +20,13 @@ # . # import json +from contextlib import contextmanager from django.conf import settings from django.contrib import messages +from django.contrib.auth import ( + BACKEND_SESSION_KEY, get_user_model, load_backend, login, +) from django.contrib.auth.mixins import LoginRequiredMixin from django.shortcuts import get_object_or_404, redirect from django.urls import reverse @@ -30,7 +34,7 @@ from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ from django.views import View from django.views.generic import ListView, TemplateView -from hijack.helpers import login_user, release_hijack +from hijack import signals from pretix.base.auth import get_auth_backends from pretix.base.models import User @@ -42,6 +46,25 @@ from pretix.control.views import CreateView, UpdateView from pretix.control.views.user import RecentAuthenticationRequiredMixin +def get_used_backend(request): + # vendored from hijack/views.py + backend_str = request.session[BACKEND_SESSION_KEY] + backend = load_backend(backend_str) + return backend + + +@contextmanager +def keep_session_age(session): + # vendored from hijack/views.py + try: + session_expiry = session["_session_expiry"] + except KeyError: + yield + else: + yield + session["_session_expiry"] = session_expiry + + class UserListView(AdministratorPermissionRequiredMixin, ListView): template_name = 'pretixcontrol/users/index.html' context_object_name = 'users' @@ -171,7 +194,28 @@ class UserImpersonateView(AdministratorPermissionRequiredMixin, RecentAuthentica 'other_email': self.object.email }) oldkey = request.session.session_key - login_user(request, self.object) + + hijacker = request.user + hijacked = self.object + + hijack_history = request.session.get("hijack_history", []) + hijack_history.append(request.user._meta.pk.value_to_string(hijacker)) + + backend = get_used_backend(request) + backend = f"{backend.__module__}.{backend.__class__.__name__}" + + with signals.no_update_last_login(), keep_session_age(request.session): + login(request, hijacked, backend=backend) + + request.session["hijack_history"] = hijack_history + + signals.hijack_started.send( + sender=None, + request=request, + hijacker=hijacker, + hijacked=hijacked, + ) + request.session['hijacker_session'] = oldkey return redirect(reverse('control:index')) @@ -180,8 +224,26 @@ class UserImpersonateStopView(LoginRequiredMixin, View): def post(self, request, *args, **kwargs): impersonated = request.user + hijs = request.session['hijacker_session'] - release_hijack(request) + hijack_history = request.session.get("hijack_history", []) + hijacked = request.user + user_pk = hijack_history.pop() + hijacker = get_object_or_404(get_user_model(), pk=user_pk) + backend = get_used_backend(request) + backend = f"{backend.__module__}.{backend.__class__.__name__}" + with signals.no_update_last_login(), keep_session_age(request.session): + login(request, hijacker, backend=backend) + + request.session["hijack_history"] = hijack_history + + signals.hijack_ended.send( + sender=None, + request=request, + hijacker=hijacker, + hijacked=hijacked, + ) + ss = request.user.get_active_staff_session(hijs) if ss: request.session.save() diff --git a/src/pretix/plugins/webcheckin/templates/pretixplugins/webcheckin/index.html b/src/pretix/plugins/webcheckin/templates/pretixplugins/webcheckin/index.html index 3d23eb4d80..bfe454788a 100644 --- a/src/pretix/plugins/webcheckin/templates/pretixplugins/webcheckin/index.html +++ b/src/pretix/plugins/webcheckin/templates/pretixplugins/webcheckin/index.html @@ -1,7 +1,6 @@ {% load compress %} {% load static %} {% load i18n %} -{% load hijack_tags %} {% load statici18n %} {% load eventurl %} {% load escapejson %} diff --git a/src/pretix/settings.py b/src/pretix/settings.py index ce3575144c..a1c8990390 100644 --- a/src/pretix/settings.py +++ b/src/pretix/settings.py @@ -390,7 +390,8 @@ for entry_point in iter_entry_points(group='pretix.plugin', name=None): PLUGINS.append(entry_point.module_name) INSTALLED_APPS.append(entry_point.module_name) -HIJACK_AUTHORIZE_STAFF = True +HIJACK_PERMISSION_CHECK = "hijack.permissions.superusers_and_staff" +HIJACK_INSERT_BEFORE = None REST_FRAMEWORK = { @@ -441,6 +442,7 @@ MIDDLEWARE = [ 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', + 'hijack.middleware.HijackUserMiddleware', 'pretix.control.middleware.PermissionMiddleware', 'pretix.control.middleware.AuditLogMiddleware', 'pretix.base.middleware.LocaleMiddleware', diff --git a/src/setup.py b/src/setup.py index 5af825d01b..e1a30c8f01 100644 --- a/src/setup.py +++ b/src/setup.py @@ -177,7 +177,7 @@ setup( 'django-formset-js-improved==0.5.0.2', 'django-formtools==2.3', 'django-hierarkey==1.0.*,>=1.0.4', - 'django-hijack>=2.2.0,<2.3.0', + 'django-hijack==3.1.*', 'django-i18nfield==1.9.*,>=1.9.4', 'django-libsass==0.9', 'django-localflavor==3.1',