openedx / openedx/openedx-authz
Make `TaxonomyOrgView` authz-aware to allow access for users with `courses.manage_tags` permission
Nobody has claimed this yet.
- 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:
- Reuse existing permissions: Do not create a new permission. Use the existing
courses.manage_tagspermission, which is already correctly assigned tocourse_editor,course_staff, andcourse_adminin theopenedx-authzpolicy. - Resolve scopes correctly: Since this endpoint receives an
orginstead of acourse_key, and authz permissions are course-scoped, you cannot simply useis_user_allowed(user, perm, org). Instead, useget_scopes_for_user_and_permission(user, action)to retrieve the course keys where the user has the permission, extract the.orgfrom those keys, and intersect it with the requestedorg. - 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
ORcondition 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
- Log in with a user who has an
openedx-authzrole (e.g.,course_editor) in a course within a specific organization, but ensure they do not have any legacy roles (likeOrgStaffRoleorOrgInstructorRole). - Navigate to a view or make a direct
GETrequest to/taxonomies/?org=<org_id>for that organization. - 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.
- Log in with an account that has a legacy org role and repeat the request to see the taxonomies load successfully.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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