Skip to content

Unify the AuthZ permission-check helpers shared across Open edX apps #558

Open

Description

@BryanttV

Description

Each app that migrates to openedx-authz currently ships its own version of the same building blocks: a combined AuthZ/legacy permission check, the legacy fallbacks, a per-HTTP-method permission mapping for DRF views, a batch permission lookup, and the logging of the access decision.

The Instructor Dashboard migration (openedx/openedx-platform#39255) added another copy, and the per-tab migrations and the other apps (Studio, libraries, etc.) will need the same pieces. Without a shared home, every app will implement and maintain its own variant, and they will drift apart.

This issue tracks the follow-up discussed in the review of openedx/openedx-platform#39255: study which of these pieces can live in openedx/core/djangoapps/authz (platform-specific, tied to the authz.enable_course_authoring flag and the legacy roles) and which in openedx-authz itself (generic), and consolidate them.

Current Behavior

The following pieces exist in more than one place or are only available inside a single app:

  • Combined AuthZ/legacy permission check. user_has_course_permission in openedx/core/djangoapps/authz/decorators.py and user_has_instructor_permission in lms/djangoapps/instructor/authz/api.py behave almost the same: with the flag enabled for the course only AuthZ is consulted, otherwise a legacy check decides.
  • Legacy checks. lms/djangoapps/instructor/authz/legacy.py holds the pre-AuthZ rules of the dashboard (has_staff_access, has_instructor_access, has_course_team_access, bridgekeeper_check, ...) next to LEGACY_PERMISSION_HANDLER_MAP in openedx/core/djangoapps/authz/constants.py.
  • Permission per HTTP method. InstructorAuthzPermission (lms/djangoapps/instructor/authz/permissions.py) maps each HTTP method of a DRF view to its AuthZ permission(s), denies the methods missing from the mapping, and falls back to the legacy rule when the flag is disabled. openedx-authz already provides the @authz_permissions decorator for per-handler permissions, and it is not clear how the two relate.
  • Batch permission lookup. get_instructor_authz_permissions returns {permission: bool} for a user in a course. openedx-authz only exposes is_user_allowed, is_user_allowed_in_any_scope and get_scopes_for_user_and_permission, so there is no batch check.
  • Decision logging. user_has_course_permission logs the decision at info level and the Instructor Dashboard _log_decision logs it at debug level, with similar but not identical extra keys (user_id, authz_permission(s), course_key, access_path).

Expected Behavior

There is a single, documented set of helpers that apps can reuse when they migrate to openedx-authz, with a clear split of responsibilities:

  • What depends on the platform (the authz.enable_course_authoring flag, legacy roles and fallbacks, decision logging) lives in openedx/core/djangoapps/authz.
  • What is generic (for example a batch permission check for a user in a scope) lives in openedx-authz.
  • The Instructor Dashboard and Studio use the shared helpers instead of their own copies, and the behavior of both is unchanged.

Acceptance Criteria

  • A short design note decides, for each piece listed in "Current Behavior", whether it lives in openedx/core/djangoapps/authz, in openedx-authz, or stays in the app, and why.
  • The relation between InstructorAuthzPermission and the @authz_permissions decorator of openedx-authz is clarified, and either one is reused or the reason to keep both is documented.
  • user_has_course_permission and user_has_instructor_permission are collapsed into a single helper (or one is built on top of the other).
  • The decision logging uses one helper, with a consistent level and consistent extra keys.
  • Any piece moved to openedx-authz has its own issue or PR in that repository, linked here.
  • Studio and Instructor Dashboard keep their current behavior, and their existing tests pass.
  • The README of openedx/core/djangoapps/authz documents the shared helpers and how an app should use them in a migration.

Out of Scope

Dependencies

  • Best started after the per-tab Instructor Dashboard migrations land, so the final shape of the helpers is clear.

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    willowReleased in Willow

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions