Skip to content

feat: grant staff access to superusers automatically#38848

Open
Abdul-Muqadim-Arbisoft wants to merge 1 commit into
openedx:masterfrom
edly-io:feat/superuser-inherits-staff
Open

feat: grant staff access to superusers automatically#38848
Abdul-Muqadim-Arbisoft wants to merge 1 commit into
openedx:masterfrom
edly-io:feat/superuser-inherits-staff

Conversation

@Abdul-Muqadim-Arbisoft

Copy link
Copy Markdown
Contributor

Description

Django's is_superuser and is_staff are independent flags. A superuser bypasses Django's permission checks, but it is is_staff that actually gates the Django admin and a number of staff-only Studio/LMS views. As a result, a superuser can end up unable to reach the admin or those views until someone also sets is_staff, which is confusing and offers no real protection, since a superuser can grant itself is_staff at any time.

This change makes every superuser a staff user automatically:

  • pre_save signal (common/djangoapps/student/signals/receivers.py), grant_staff_access_to_superusers sets is_staff = True on any user being saved with is_superuser = True. It runs before the DB write, so there is no
    extra query and no signal recursion. Fixture (raw) loads are skipped.
  • Data migration (student/migrations/0050_grant_staff_to_existing_superusers.py), backfills existing superusers (is_superuser=True, is_staff=False → is_staff=True) in a single bulk update, since the signal only affects future saves. The
    reverse operation is intentionally a no-op.

Behavior is one-directional by design: it grants staff to superusers but does not remove staff when a user stops being a superuser.

Supporting information

Forum discussion: https://discuss.openedx.org/t/shouldnt-superuser-automatically-inherit-staff-access-in-open-edx/18657

Feanil suggested "a small signal handler or something that would just grant all superusers the staff role as well", this implements exactly that, plus a one-time backfill for existing installs.

Testing instructions

  1. Create a superuser via the Django admin or shell with is_superuser=True and is_staff=False, save it, and confirm is_staff is now True.
  2. Promote an existing non-staff user to superuser and confirm they gain staff access.
  3. Confirm a regular (non-superuser) user's is_staff value is left untouched.
  4. On an existing install with a non-staff superuser, run migrations and confirm that superuser becomes staff.

Django's is_superuser and is_staff are independent flags, so a superuser
does not get the is_staff access that gates the Django admin and various
staff-only Studio/LMS views. Since a superuser can grant itself is_staff
at any time, that split offers no protection and is only surprising.

Add a pre_save signal on the User model that marks any superuser as staff,
and a data migration to backfill existing superusers.

Discussion: https://discuss.openedx.org/t/shouldnt-superuser-automatically-inherit-staff-access-in-open-edx/18657
@Abdul-Muqadim-Arbisoft Abdul-Muqadim-Arbisoft force-pushed the feat/superuser-inherits-staff branch from f5defd9 to 8eccf6e Compare July 4, 2026 21:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant