diff --git a/authentication/pipeline/user.py b/authentication/pipeline/user.py index 4ca966802a..40f9a7a9dc 100644 --- a/authentication/pipeline/user.py +++ b/authentication/pipeline/user.py @@ -218,7 +218,7 @@ def forbid_hijack(strategy, backend, **kwargs): # pylint: disable=unused-argume backend (social_core.backends.base.BaseAuth): the backend being used to authenticate """ # As first step in pipeline, stop a hijacking admin from going any further - if strategy.session_get("is_hijacked_user"): + if bool(strategy.session_get("hijack_history")): raise AuthException("You are hijacking another user, don't try to login again") # noqa: EM101 return {} diff --git a/authentication/views.py b/authentication/views.py index 2fecc6b000..72dec89ca6 100644 --- a/authentication/views.py +++ b/authentication/views.py @@ -48,7 +48,7 @@ def get_serializer_cls(self): # pragma: no cover def post(self, request): """Processes a request""" - if request.session.get("is_hijacked_user", False): + if bool(request.session.get("hijack_history")): return Response(status=status.HTTP_403_FORBIDDEN) serializer_cls = self.get_serializer_cls() @@ -90,7 +90,7 @@ def get_serializer_cls(self): def post(self, request): """Verify recaptcha response before proceeding""" - if request.session.get("is_hijacked_user", False): + if bool(request.session.get("hijack_history")): return Response(status=status.HTTP_403_FORBIDDEN) if settings.RECAPTCHA_SITE_KEY: r = requests.post( # noqa: S113 diff --git a/authentication/views_test.py b/authentication/views_test.py index 5ed05f0797..3a89984f5d 100644 --- a/authentication/views_test.py +++ b/authentication/views_test.py @@ -589,7 +589,7 @@ def test_login_email_error(client, mocker): def test_login_email_hijacked(client, user, admin_user): """Test that a 403 response is returned for email login view if user is hijacked""" client.force_login(admin_user) - client.post(f"/hijack/{user.id}/") + client.post("/hijack/acquire/", {"user_pk": user.id}) response = client.post( reverse("psa-login-email"), {"flow": SocialAuthState.FLOW_LOGIN, "email": "anything@example.com"}, @@ -600,7 +600,7 @@ def test_login_email_hijacked(client, user, admin_user): def test_register_email_hijacked(client, user, admin_user): """Test that a 403 response is returned for email register view if user is hijacked""" client.force_login(admin_user) - client.post(f"/hijack/{user.id}/") + client.post("/hijack/acquire/", {"user_pk": user.id}) response = client.post( reverse("psa-register-email"), {"flow": SocialAuthState.FLOW_LOGIN, "email": "anything@example.com"}, diff --git a/cms/models_test.py b/cms/models_test.py index 11abe9a5d6..2ad3bf42f7 100644 --- a/cms/models_test.py +++ b/cms/models_test.py @@ -166,6 +166,7 @@ def test_course_page_context( # noqa: PLR0913 "can_access_edx_course": is_authenticated and has_relevant_run, "finaid_price": finaid_price, "product": product, + "hijack_logout_redirect_url": "/admin/users/user", "instructors": [] if not has_instructor else [ diff --git a/frontend/public/scss/common.scss b/frontend/public/scss/common.scss index 9be5a4080e..f1e2f0dc64 100644 --- a/frontend/public/scss/common.scss +++ b/frontend/public/scss/common.scss @@ -261,3 +261,18 @@ button.btn-secondary.unstyled { .display-none { display: none !important; } + +.djhj { + position: relative !important; + top: 0; + + .djhj-message, .djhj-actions { + width: fit-content; + } + + .djhj-notification { + max-width: unset; + background: $navy-blue; + margin: 0; + } +} diff --git a/main/settings.py b/main/settings.py index 6c156307ff..0552268302 100644 --- a/main/settings.py +++ b/main/settings.py @@ -200,9 +200,8 @@ # "compliance", "openedx", # must be after "users" to pick up custom user model - "compat", "hijack", - "hijack_admin", + "hijack.contrib.admin", "ecommerce", "flexiblepricing", "micromasters_import", @@ -235,6 +234,7 @@ "django.middleware.clickjacking.XFrameOptionsMiddleware", "django.contrib.sites.middleware.CurrentSiteMiddleware", "django_user_agents.middleware.UserAgentMiddleware", + "hijack.middleware.HijackUserMiddleware", "main.middleware.CachelessAPIMiddleware", "wagtail.contrib.redirects.middleware.RedirectMiddleware", ) diff --git a/main/templates/base.html b/main/templates/base.html index 7561cfecaf..6493c66a33 100644 --- a/main/templates/base.html +++ b/main/templates/base.html @@ -1,4 +1,4 @@ -{% load static hijack_tags js_interop %} +{% load static hijack js_interop %} {% load wagtailcore_tags startswith noindex_meta banner %} {% load render_bundle from webpack_loader %} @@ -33,7 +33,8 @@
Skip to main content {% include "partials/gtm_body.html" %} - {% hijack_notification %} + + {% include 'hijack/notification.html' %} {% if not request.path|startswith:'/certificate/' %} {% banner %} {% block headercontent %} diff --git a/main/templates/hijack/notification.html b/main/templates/hijack/notification.html new file mode 100644 index 0000000000..3aa25f211c --- /dev/null +++ b/main/templates/hijack/notification.html @@ -0,0 +1,20 @@ + + +{% load static %} +{% if request.user.is_hijacked %} + +
+
+
+ You are currently working on behalf of {{ request.user.username }}. +
+
+ {% csrf_token %} + + +
+
+
+{% endif %} diff --git a/main/views.py b/main/views.py index 48069a4f5a..baf618483c 100644 --- a/main/views.py +++ b/main/views.py @@ -21,6 +21,7 @@ def get_base_context(request): # noqa: ARG001 context["domain_verification_tag"] = ( settings.GOOGLE_DOMAIN_VERIFICATION_TAG_VALUE ) + context["hijack_logout_redirect_url"] = settings.HIJACK_LOGOUT_REDIRECT_URL return context diff --git a/poetry.lock b/poetry.lock index 7bfaaa818f..8bbf1094cb 100644 --- a/poetry.lock +++ b/poetry.lock @@ -982,19 +982,6 @@ amazon-ses = ["boto3 (>=1.10.17)"] postal = ["cryptography"] resend = ["svix"] -[[package]] -name = "django-compat" -version = "1.0.15" -description = "For- and backwards compatibility layer for Django 1.4, 1.7, 1.8, 1.9, 1.10, and 1.11" -optional = false -python-versions = "*" -files = [ - {file = "django-compat-1.0.15.tar.gz", hash = "sha256:3ac9a3bedc56b9365d9eb241bc5157d0c193769bf995f9a78dc1bc24e7c2331b"}, -] - -[package.dependencies] -six = ">=1.10.0" - [[package]] name = "django-cors-headers" version = "3.14.0" @@ -1086,34 +1073,20 @@ django-fsm = ">=2.1.0" [[package]] name = "django-hijack" -version = "2.3.0" +version = "3.4.5" description = "django-hijack allows superusers to hijack (=login as) and work on behalf of another user." optional = false python-versions = "*" files = [ - {file = "django-hijack-2.3.0.tar.gz", hash = "sha256:216de6ff863b5f48314795083e96267ff0829ff7f7180c26ca3c17d8a134e1cf"}, - {file = "django_hijack-2.3.0-py3-none-any.whl", hash = "sha256:8b820b6fe605cf2f3b50817985d7245285a18c027b7e3eb424d18b7908ecd2e1"}, -] - -[package.dependencies] -django = ">=2.2" - -[[package]] -name = "django-hijack-admin" -version = "2.1.10" -description = "Django admin integration for Django Hijack (https://github.com/arteria/django-hijack/)" -optional = false -python-versions = "*" -files = [ - {file = "django-hijack-admin-2.1.10.tar.gz", hash = "sha256:330f9be331ada831248c9cee5a21202aea70fb9911b443249ce4c28d57d9e2e3"}, + {file = "django-hijack-3.4.5.tar.gz", hash = "sha256:7e45b1de786bdc130628e4230b359dde6d8744ecd3bcd668d2b27c5d614a071c"}, + {file = "django_hijack-3.4.5-py3-none-any.whl", hash = "sha256:129cbe75444b163135871a947d38ffb72181f4f2583544703fc9efe083c9ddad"}, ] [package.dependencies] -django-compat = ">=1.0.13" -django-hijack = ">=2.1.5" +django = ">=3.2" [package.extras] -dev = ["flake8"] +test = ["pytest", "pytest-cov", "pytest-django"] [[package]] name = "django-ipware" @@ -4247,4 +4220,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "3.9.18" -content-hash = "895c86bcf09a319053bad44d1ed8e96bdf8d66a17076f3df9285279921bdf947" +content-hash = "bcef460938d1ab6d8be34d5f5d159ef8d3d46900023593500c5a26f667aac5d7" diff --git a/pyproject.toml b/pyproject.toml index 68a15063fa..215ad9d3d7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,8 +25,7 @@ django-countries = "^7.2.1" django-filter = "^2.4.0" django-fsm = "^2.8.0" django-fsm-admin = "^1.2.4" -django-hijack = "^2.1.10" -django-hijack-admin = "^2.1.10" +django-hijack = "^3.0.0" django-ipware = "^4.0.0" django-oauth-toolkit = "^1.7.0" django-redis = "^5.0.0" diff --git a/users/admin.py b/users/admin.py index 30d9b539ec..becb7a3d83 100644 --- a/users/admin.py +++ b/users/admin.py @@ -3,7 +3,7 @@ from django.contrib import admin from django.contrib.auth.admin import UserAdmin as ContribUserAdmin from django.utils.translation import gettext_lazy as _ -from hijack_admin.admin import HijackUserAdminMixin +from hijack.contrib.admin import HijackUserAdminMixin from mitol.common.admin import TimestampedModelAdmin from users.models import BlockList, LegalAddress, User, UserProfile @@ -88,7 +88,6 @@ class UserAdmin(ContribUserAdmin, HijackUserAdminMixin, TimestampedModelAdmin): "email", "name", "is_staff", - "hijack_field", "last_login", ) list_filter = ("is_staff", "is_superuser", "is_active", "groups")