openedx / openedx/openedx-platform
Task - RBAC Authz - Implement taxonomy permissions
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 8.2k
- Forks
- 4.4k
- Avg merge
- 6d 18h
- Merged PRs (30d)
- 42
Description
Task - RBAC Authz - Implement taxonomy permissions
Context
openedx-platform#38436 added authz permission checks for the object tag endpoints (ObjectTagOrgView) and the xblock outline handler. However, the taxonomy-related endpoints still rely entirely on legacy org-level roles to determine access. Users with authz-only course roles (e.g. course_editor without legacy CourseStaffRole) cannot view, browse, or interact with taxonomies anywhere in course authoring.
This affects any surface in Studio that calls taxonomy endpoints — the content tags drawer, the taxonomy management pages, tag import/export, and any other course authoring feature that lists or browses taxonomies.
This is a continuation of the work started in #38143.
Endpoint inventory
Endpoints called from frontend-app-authoring.
Object tag endpoints (already fixed in #38436)
| Endpoint | Method | Called from | Status |
|---|---|---|---|
/object_tags/{contentId}/ |
GET | Content tags drawer — load applied tags | ✅ Fixed |
/object_tags/{contentId}/ |
PUT | Content tags drawer — save tag changes | ✅ Fixed |
/object_tag_counts/{contentId}/ |
GET | Content tags drawer, course outline — tag count badge | ✅ No auth checks (by design) |
/object_tags/{courseId}/export/ |
GET | Course outline — export tags CSV | ✅ Fixed (uses has_view_object_tags_access) |
Taxonomy list and detail endpoints (affected)
| Endpoint | Method | Called from | Permission layer | Status |
|---|---|---|---|---|
/taxonomies/?enabled=true&org=X |
GET | Content tags drawer (with org from content ID), taxonomy management page | UserOrgFilterBackend → get_user_orgs / get_admin_orgs |
❌ Broken |
/taxonomies/{pk}/ |
GET | Taxonomy detail page | TaxonomyObjectPermissions → oel_tagging.view_taxonomy → can_view_taxonomy |
❌ Broken (org-scoped) |
/taxonomies/{pk}/ |
PATCH | Taxonomy detail page — edit taxonomy | TaxonomyObjectPermissions → oel_tagging.change_taxonomy |
❌ Likely broken |
/taxonomies/{pk}/ |
DELETE | Taxonomy management page — delete taxonomy | TaxonomyObjectPermissions → oel_tagging.delete_taxonomy |
❌ Likely broken |
Taxonomy tags endpoints (affected)
| Endpoint | Method | Called from | Permission layer | Status |
|---|---|---|---|---|
/taxonomies/{pk}/tags/ |
GET | Content tags drawer (browse/search tags), taxonomy detail page (tag list) | TaxonomyTagsObjectPermissions → oel_tagging.list_tag → can_view_taxonomy |
❌ Broken (org-scoped) |
/taxonomies/{pk}/tags/ |
POST | Taxonomy detail page — create tag | TaxonomyTagsObjectPermissions → oel_tagging.add_tag |
❌ Likely broken |
/taxonomies/{pk}/tags/ |
PUT | Taxonomy detail page — update tag | TaxonomyTagsObjectPermissions → oel_tagging.change_tag |
❌ Likely broken |
/taxonomies/{pk}/tags/ |
DELETE | Taxonomy detail page — delete tag | TaxonomyTagsObjectPermissions → oel_tagging.delete_tag |
❌ Likely broken |
Taxonomy import/export endpoints (affected)
| Endpoint | Method | Called from | Permission layer | Status |
|---|---|---|---|---|
/taxonomies/import/ |
POST | Taxonomy management page — create taxonomy from import | TaxonomyObjectPermissions |
❌ Likely broken |
/taxonomies/{pk}/tags/import/ |
PUT | Taxonomy detail page — import tags | TaxonomyTagsObjectPermissions |
❌ Likely broken |
/taxonomies/{pk}/tags/import/plan/ |
PUT | Taxonomy detail page — preview import | TaxonomyTagsObjectPermissions |
❌ Likely broken |
/taxonomies/{pk}/export/ |
GET | Taxonomy detail page — export taxonomy | No auth (direct download URL) | ⚠️ Needs investigation |
/taxonomies/import/template.{ext} |
GET | Taxonomy management page — download template | No auth | ✅ Fine |
Taxonomy org management endpoint (affected)
| Endpoint | Method | Called from | Permission layer | Status |
|---|---|---|---|---|
/taxonomies/{pk}/orgs/ |
PUT | Taxonomy detail page — manage org associations | oel_tagging.update_orgs |
❌ Likely broken |
Root cause
All "broken" endpoints share the same root cause: permission checks resolve the user's org membership via legacy roles (get_user_orgs, get_admin_orgs, is_org_user, is_org_admin). Authz-only users have no legacy roles, so these checks fail.
The key functions that need authz-aware paths:
UserOrgFilterBackend.filter_queryset— taxonomy list filteringcan_view_taxonomy— django-rules predicate used by multiple permission classesis_org_user/is_org_admin— underlying org membership checks
Design considerations
- These endpoints don't always have a course context available. The taxonomy management page calls them without any course/content reference. An authz path may need to use
get_scopes_for_user_and_permissionto resolve the user's orgs from their authz role assignments, or the frontend may need to pass a content ID where applicable (see companion frontend issue). - The
can_view_taxonomypredicate is the most impactful fix — it underpinsview_taxonomy,list_tag, and is used by bothTaxonomyObjectPermissionsandTaxonomyTagsObjectPermissions. - Write operations (PATCH, DELETE, POST on taxonomies/tags) may need separate authz permissions (e.g.
courses.manage_taxonomies) beyond just org membership. - Library tagging should be unaffected — non-course objects fall through to legacy permissions.
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 with UserOrgFilterBackend.filter_queryset and the can_view_taxonomy predicate, then trace is_org_user and is_org_admin through the taxonomy permission classes and listed endpoints. Determine how authz-only course roles should resolve organization access and whether write operations need separate permissions. Done means taxonomy viewing and management work for eligible authz-only users while library tagging retains its legacy behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- authorization, backend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100