openedx / openedx/openedx-authz

Make `TaxonomyOrgView` authz-aware to allow access for users with `courses.manage_tags` permission

Open
#448 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

willow
Dominant language
Python
Stars
0
Forks
9
Avg merge
13d 9h
Merged PRs (30d)
9

Description

Description

Currently, TaxonomyOrgView (which handles GET /taxonomies/?org=X) uses UserOrgFilterBackend, which relies on legacy role resolution (get_admin_orgs/get_user_orgs in rules.py). This means it only recognizes legacy roles (like OrgStaffRole, OrgInstructorRole, etc.). Users with openedx-authz roles, such as course_editor, return an empty list and hit queryset.none(), preventing them from seeing even global taxonomies.

To fix this, we need to extend the authz-aware pattern already used in ObjectTagTaxonomyOrgFilterBackend to UserOrgFilterBackend.

Key technical requirements for the solution:

  1. Reuse existing permissions: Do not create a new permission. Use the existing courses.manage_tags permission, which is already correctly assigned to course_editor, course_staff, and course_admin in the openedx-authz policy.
  2. Resolve scopes correctly: Since this endpoint receives an org instead of a course_key, and authz permissions are course-scoped, you cannot simply use is_user_allowed(user, perm, org). Instead, use get_scopes_for_user_and_permission(user, action) to retrieve the course keys where the user has the permission, extract the .org from those keys, and intersect it with the requested org.
  3. Additive logic (OR): This endpoint also serves Content Libraries (which use legacy roles) and courses where the authz toggle is disabled. The new authz check must be added as an OR condition to the legacy filter, rather than replacing it.
Expected Behavior

When a user with the courses.manage_tags permission requests taxonomies for a specific organization (GET /taxonomies/?org=X), the backend should successfully return the taxonomies. The system must evaluate the user's allowed scopes using get_scopes_for_user_and_permission, extract the organizations from those scopes, and allow access if there's a match, working seamlessly alongside the legacy role checks.

Current Behavior

UserOrgFilterBackend strictly evaluates legacy roles. If a user only has an openedx-authz role like course_editor, the legacy resolution returns empty lists, forcing an early queryset.none() return. This blocks the user from seeing any taxonomies, including global ones (where org=None).

Steps to reproduce
  1. Log in with a user who has an openedx-authz role (e.g., course_editor) in a course within a specific organization, but ensure they do not have any legacy roles (like OrgStaffRole or OrgInstructorRole).
  2. Navigate to a view or make a direct GET request to /taxonomies/?org=<org_id> for that organization.
  3. Observe that the endpoint returns an empty result (or the UI fails to display taxonomies) because the user's authz roles are completely ignored by the current filter backend.
  4. Log in with an account that has a legacy org role and repeat the request to see the taxonomies load successfully.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at UserOrgFilterBackend and compare its legacy role handling in rules.py with the authz-aware pattern in ObjectTagTaxonomyOrgFilterBackend. Trace GET /taxonomies/?org=X and get_scopes_for_user_and_permission, then verify that legacy and authz access both work for organization-specific and global taxonomies.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
authorization, backend-api-design
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.