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_tags permission, which is already correctly assigned to course_editor, course_staff, and course_admin in the openedx-authz policy.
- 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.
- 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
- 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).
- Navigate to a view or make a direct
GET request 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.
Description
Currently,
TaxonomyOrgView(which handlesGET /taxonomies/?org=X) usesUserOrgFilterBackend, which relies on legacy role resolution (get_admin_orgs/get_user_orgsinrules.py). This means it only recognizes legacy roles (likeOrgStaffRole,OrgInstructorRole, etc.). Users withopenedx-authzroles, such ascourse_editor, return an empty list and hitqueryset.none(), preventing them from seeing even global taxonomies.To fix this, we need to extend the authz-aware pattern already used in
ObjectTagTaxonomyOrgFilterBackendtoUserOrgFilterBackend.Key technical requirements for the solution:
courses.manage_tagspermission, which is already correctly assigned tocourse_editor,course_staff, andcourse_adminin theopenedx-authzpolicy.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.ORcondition to the legacy filter, rather than replacing it.Expected Behavior
When a user with the
courses.manage_tagspermission 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 usingget_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
UserOrgFilterBackendstrictly evaluates legacy roles. If a user only has anopenedx-authzrole likecourse_editor, the legacy resolution returns empty lists, forcing an earlyqueryset.none()return. This blocks the user from seeing any taxonomies, including global ones (whereorg=None).Steps to reproduce
openedx-authzrole (e.g.,course_editor) in a course within a specific organization, but ensure they do not have any legacy roles (likeOrgStaffRoleorOrgInstructorRole).GETrequest to/taxonomies/?org=<org_id>for that organization.