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',