Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ Added
``openedx_authz/engine/schema/paragon_icons.py`` and regenerated with
``make paragon_icons`` (ADR 0029).

Changed
========

* Removed ``authz.policy`` and Casbin action grouping. Built-in roles list every permission explicitly in the authorization schema, so the existing ``g2`` rows did not change their access. Migration ``0012_remove_action_grouping`` removes stored ``g2`` rows from existing databases.
* Calls to the deprecated ``load_policies`` command without an explicit policy file are now a no-op while deployment integrations move to ``load_authz_schema``.

Notes
=====

Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Integration with edx-platform

This repository became an edx-platform's dependency starting with the Ulmo release. From that release onwards, system policies are automatically updated.

If you need to update the policies manually, it is recommended to use the ``./manage.py lms load_policies`` command.
To update the static authorization definitions manually, run ``./manage.py lms load_authz_schema``.

.. note::
Currently, this package only supports the `content libraries' roles and permissions as documented here`_, and the migration of data from the old system to the new one is performed automatically.
Expand Down
11 changes: 11 additions & 0 deletions docs/decisions/0022-defer-authorization-implications.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ Consequences
* The current policy loader continues to handle existing Casbin grouping rows.
* Introducing implication later requires a schema-version change and migration guidance.

Addendum: Remove Existing Action Grouping (2026-10-16)
======================================================

The built-in roles list every permission covered by the existing ``g2`` action-grouping rows, so those rows do not change their effective permissions. The Casbin model now uses exact action matches and a data migration removes stored ``g2`` rows.

Permission grouping and role inheritance remain future work in `Issue #91`_ and `Issue #523`_. Any later implementation still requires the schema-version change and migration guidance described in this ADR.

Rejected Alternatives
*********************

Expand All @@ -62,5 +69,9 @@ References
**********

* `ADR 0017`_
* `Issue #91`_
* `Issue #523`_

.. _ADR 0017: 0017-static-authorization-schema.rst
.. _Issue #91: https://github.com/openedx/openedx-authz/issues/91
.. _Issue #523: https://github.com/openedx/openedx-authz/issues/523
2 changes: 1 addition & 1 deletion src/openedx_authz/authz/schema/course_permissions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ permission_categories:
description: Additional permissions not included in other categories, such as viewing checklists.
icon: DrawShapes
# Backend-only category for legacy compatibility actions that have no frontend
# display metadata. These are referenced by legacy roles in authz.policy.
# display metadata. These are referenced by legacy roles in course_roles.yaml.
- id: course_legacy
display_name: Legacy compatibility
description: Internal compatibility permissions that map legacy course roles to the authorization system. Not shown as individually assignable permissions.
Expand Down
190 changes: 0 additions & 190 deletions src/openedx_authz/engine/config/authz.policy

This file was deleted.

19 changes: 2 additions & 17 deletions src/openedx_authz/engine/config/model.conf
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
#
# This model supports:
# - Scoped role assignments (user roles tied to specific contexts)
# - Action grouping (manage → read/write/edit/delete to reduce duplication)
# - System-wide roles (global scope "*" applies everywhere)
# - Negative rules (deny overrides allow for exceptions)
# - Namespace support (user^, role^, act^, lib^, org^, course^, etc.)
Expand Down Expand Up @@ -52,16 +51,6 @@ p = sub, act, scope, eft
# g, role^org_admin, role^org_editor, org^OpenedX # org_admin inherits org_editor permissions
g = _, _, _

# g2: Action grouping and implications
# Maps high-level actions to specific actions to reduce policy duplication
#
# Examples:
# g2, act^manage, act^edit # manage implies edit
# g2, act^manage, act^delete # manage implies delete
# g2, act^edit_courses, act^read # edit_courses implies read (for resource access)
# g2, act^edit_courses, act^write # edit_courses implies write (for resource modification)
g2 = _, _

[policy_effect]
# Deny-override policy: allow if any rule allows AND no rule denies
# This enables negative rules/exceptions (e.g., "manage all courses except course Z")
Expand All @@ -84,12 +73,8 @@ e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
# SCOPE MATCHING:
# - keyMatch(r.scope, p.scope): scope matches pattern
#
# ACTION MATCHING:
# - r.act == p.act: exact action match
# - g2(p.act, r.act): policy action implies requested action via grouping
#
# All conditions must be true for a policy to match:
# 1. Subject must have role in scope OR global role
# 2. Scope must match pattern
# 3. Action must match OR inherit via action grouping
m = is_staff_or_superuser(r.sub, r.act, r.scope) || (g(r.sub, p.sub, r.scope) || g(r.sub, p.sub, "*")) && keyMatch(r.scope, p.scope) && (r.act == p.act || g2(p.act, r.act))
# 3. Action must match exactly
m = is_staff_or_superuser(r.sub, r.act, r.scope) || (g(r.sub, p.sub, r.scope) || g(r.sub, p.sub, "*")) && keyMatch(r.scope, p.scope) && r.act == p.act
4 changes: 0 additions & 4 deletions src/openedx_authz/engine/filter.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,27 @@ class Filter:

- ``p`` → Policy rule (permissions).
- ``g`` → Grouping rule (user ↔ role).
- ``g2`` → Action grouping (parent action ↔ child action).
"""

v0: Optional[list[str]] = attr.field(factory=list)
"""v0 (Optional[list[str]]): First policy value filter.

- For ``p`` → Subject (e.g., ``role^org_admin``, ``user^alice``).
- For ``g`` → User (e.g., ``user^alice``).
- For ``g2`` → Parent action (e.g., ``act^manage``).
"""

v1: Optional[list[str]] = attr.field(factory=list)
"""v1 (Optional[list[str]]): Second policy value filter.

- For ``p`` → Action (e.g., ``act^manage``, ``act^edit``).
- For ``g`` → Role (e.g., ``role^org_admin``).
- For ``g2`` → Child action (e.g., ``act^edit``).
"""

v2: Optional[list[str]] = attr.field(factory=list)
"""v2 (Optional[list[str]]): Third policy value filter.

- For ``p`` → Object or resource (e.g., ``lib^*``, ``org^MIT``).
- For ``g`` → Scope or resource (e.g., ``org^MIT``).
- For ``g2`` → Not used.
"""

v3: Optional[list[str]] = attr.field(factory=list)
Expand Down
Loading
Loading