|
| 1 | +0002: Authorization (AuthZ) Model Foundations |
| 2 | +############################################# |
| 3 | + |
| 4 | +Status |
| 5 | +****** |
| 6 | +**Draft** |
| 7 | + |
| 8 | +Context |
| 9 | +******* |
| 10 | +Open edX needs a single way to decide: who can do what, on which resource, and under which conditions. Today, permissions are checked in many different ways. Some systems are feature-specific (``student_courseaccessrole``, ``django_comment_client_role``, ``contentlibrarypermission``). Others use global roles passed in JWTs. Many checks are written directly in code (``if user.is_superuser``). This makes the system hard to extend, hard to change, and not easy to audit. |
| 11 | + |
| 12 | +We want an authorization model that is: |
| 13 | + |
| 14 | +* Clear and consistent vocabulary everywhere. |
| 15 | +* Explicitly supports industry standards and is built on battle-tested technologies. |
| 16 | +* Flexible but still simple to maintain. |
| 17 | +* Able to explain every decision (the system should be transparent on why access was granted or not). |
| 18 | +* Unified and centralized enforcement rather than ad-hoc implementations for immediate needs. |
| 19 | +* Able to support query-based access patterns out of the box. |
| 20 | +* Focused on connecting stakeholders and making policies clear and accessible to everyone involved. |
| 21 | + |
| 22 | +.. note:: |
| 23 | + |
| 24 | + Authorization is considered independent from authentication. There will be an interface between them so we can combine correctness and consistency. A separate ADR will cover the details of this interface (e.g., how roles in JWTs are handled and how checks are made). |
| 25 | + |
| 26 | +Decision |
| 27 | +******** |
| 28 | + |
| 29 | +I. Canonical Permission Model |
| 30 | +============================= |
| 31 | + |
| 32 | +Normalize all checks to Subject-Action-Object-Context (S-A-O-C) |
| 33 | +---------------------------------------------------------------- |
| 34 | +* We express authorization as: is **Subject** allowed to do **Action** on **Object** under **Context**? |
| 35 | +* This normalization is used in policies, code, queries, and audits. |
| 36 | +* Examples: |
| 37 | + |
| 38 | + - Can Alice (subject) edit (action) Course 123 (object) as part of Org A (context)? |
| 39 | + - Can a service account (subject) read (action) Library X (object) during maintenance mode (context)? |
| 40 | + |
| 41 | +II. Resources and Scopes |
| 42 | +======================== |
| 43 | + |
| 44 | +Scopes as first-class citizens in permission-granting |
| 45 | +----------------------------------------------------- |
| 46 | +* A **scope** defines the boundary within which a role or policy applies (for example: platform-wide, organization-wide, a single course, or a specific library). |
| 47 | +* Treating scopes as **first-class citizens** means they are explicitly modeled in the system, not hidden inside ad-hoc resource definitions. They must be available to policies, queries, and audits in a consistent way. |
| 48 | +* Scopes can be **parameterized** (e.g., ``organization:ORG-A``, ``course:CS101``, ``site:sandbox.openedx.org``, ``instance``) to support granular checks. |
| 49 | +* **Inheritance across scopes** must be supported (e.g., permissions granted at the organization level can cascade to courses in that organization when intended). |
| 50 | +* By making scopes explicit and consistent, we avoid the fragmentation seen in legacy systems (different services using different implicit notions of "site", "org", "course"). |
| 51 | + |
| 52 | +III. Authorization Paradigm |
| 53 | +=========================== |
| 54 | + |
| 55 | +Adopt ABAC as the goal; Scoped RBAC as a first step |
| 56 | +--------------------------------------------------- |
| 57 | +* We recommend **ABAC** as the main model for Open edX authorization. |
| 58 | +* **Scoped RBAC** may be used pragmatically as a first step, with the ambition of moving into a more granular system with ABAC. |
| 59 | +* **RBAC** handles role-based permissions well (e.g., "admins can edit any record"). |
| 60 | +* **ABAC** adds finer control by using attributes of subjects, resources, and context (e.g., "editors can edit only in their assigned organizations or locations"). |
| 61 | +* **ReBAC** is not chosen because it adds complexity and we do not have strong use cases today. |
| 62 | + |
| 63 | + - Although ReBAC solves interesting problems out of the box (inheritance, recursive relationships), it introduces a mental shift in how to think about authorization. |
| 64 | + - Some technologies are ReBAC-first but can also implement RBAC and ABAC effectively. These are not excluded, but they shouldn't go against our **simplicity principle**. |
| 65 | + |
| 66 | +* **Simplicity principle**: avoid adding features like deep role inheritance or complex hierarchies until there are clear use cases that require them. |
| 67 | + |
| 68 | +IV. Policy Definition |
| 69 | +===================== |
| 70 | + |
| 71 | +Externalize policies |
| 72 | +-------------------- |
| 73 | +* Policies must be defined outside code, not hardcoded with conditionals. |
| 74 | + |
| 75 | + - Prefer declarative policy definitions (e.g., JSON, YAML, policy language) over in-code checks like ``if user.is_superuser``. |
| 76 | + - Prefer explicit permission checks over implicit role lookups in business logic. |
| 77 | + |
| 78 | +* Policies must explicitly show whether access comes from: |
| 79 | + |
| 80 | + - **Default roles** (out-of-the-box), or |
| 81 | + - **Extensions** (plugin-based). |
| 82 | + |
| 83 | +* Policies must be versioned, reviewable, and easy to share. |
| 84 | +* If policies are not easy to read, provide an abstracted or friendly view. |
| 85 | +* Show the **effect** of policies when available (allow/deny). |
| 86 | + |
| 87 | +V. Enforcement |
| 88 | +============== |
| 89 | + |
| 90 | +Use centralized enforcement |
| 91 | +--------------------------- |
| 92 | +* Authorization checks must go through a single path, not spread across ad-hoc implementations. |
| 93 | +* Centralized enforcement can take two possible forms: |
| 94 | + |
| 95 | + - A **central service** that acts as the decision point for all checks. |
| 96 | + - A **shared adapter/library** that is the only way services can ask for permissions. |
| 97 | + |
| 98 | +* In both cases, services must not embed authorization logic directly. |
| 99 | + |
| 100 | +VI. Engines and Integration |
| 101 | +============================ |
| 102 | + |
| 103 | +Use proven frameworks with ABAC support and an adapter |
| 104 | +------------------------------------------------------ |
| 105 | +* Use existing open source frameworks (Casbin, Cerbos, OpenFGA, SpiceDB). |
| 106 | +* Do not build a custom engine. |
| 107 | +* The chosen technology must: |
| 108 | + |
| 109 | + - Support **ABAC** to allow growth beyond role-only systems. |
| 110 | + - Provide **explicit and clear permission checks** in code, similar in clarity to Django's ``user.has_perm``. |
| 111 | + - Avoid introducing obscure or confusing query styles. |
| 112 | + |
| 113 | +* Provide an **adapter layer** that: |
| 114 | + |
| 115 | + - Translates Open edX concepts into the engine model. |
| 116 | + - Keeps Open edX services engine-agnostic. |
| 117 | + - Ensures consistent logging and decision tracing. |
| 118 | + |
| 119 | +VII. Extensibility |
| 120 | +=================== |
| 121 | + |
| 122 | +Make roles, permissions, and models pluggable |
| 123 | +--------------------------------------------- |
| 124 | +* Extensibility should include: |
| 125 | + |
| 126 | + - Adding **custom roles** that can be composed from or unioned with existing permissions. |
| 127 | + - Adding **new permissions (verbs)** that build on top of existing ones. |
| 128 | + - Defining **new models/resources** (e.g., "workspace", "assignment") and expressing their relations to existing ones (e.g., platform → organization → course). |
| 129 | + |
| 130 | +* Applications must keep calling the same consistent check (e.g., *can(subject, action, object)*), while the schema or policy evolves underneath. |
| 131 | + |
| 132 | +VIII. Auditability |
| 133 | +================= |
| 134 | + |
| 135 | +Make all decisions explainable |
| 136 | +------------------------------ |
| 137 | +* Every decision must have a trace: |
| 138 | + |
| 139 | + - Which policy was used. |
| 140 | + - Which attributes were checked. |
| 141 | + - The effect (allow/deny). |
| 142 | + |
| 143 | +* Logs must let admins ask: "Why was this action allowed or denied?" |
| 144 | +* Traces must capture runtime values so audits remain possible later. |
| 145 | +* Permission checks in code must be **explicit and self-documenting**, so developers and stakeholders can easily understand how authorization is asked for in the system. |
| 146 | + |
| 147 | +IX. Security |
| 148 | +============ |
| 149 | + |
| 150 | +Protect policies and logs against tampering |
| 151 | +-------------------------------------------- |
| 152 | + |
| 153 | +* The system must guarantee the integrity of authorization policies and decision logs. |
| 154 | +* Policies and logs should be stored or managed in a way that makes tampering detectable. |
| 155 | + |
| 156 | +Consequences |
| 157 | +************ |
| 158 | +1. **Strong audit needs.** We must build a central log of all decisions, including attributes and matched policies. |
| 159 | +2. **Attribute management.** ABAC requires attributes to be available and normalized. We must also capture their values in logs. |
| 160 | +3. **Scoped RBAC transition.** Some parts may use RBAC first, but the chosen system must support full ABAC. |
| 161 | +4. **Readable policies.** Even if technical, policies must be presented in a way non-technical people can review. |
| 162 | +5. **Scope consistency.** The system must provide a consistent definition and handling of scopes and resource hierarchies across all services, so that policies and checks have the same meaning everywhere. |
| 163 | +6. **Performance impact.** Logging and attributes add overhead. We must design caching and retention strategies. |
| 164 | +7. **Migration work.** Old in-code checks must be replaced step by step with policies. |
| 165 | +8. **Querying system.** The authorization model must support query-style checks (e.g., "list all objects this user can edit") at least as well as the current bridgekeeper system, either by integration or by providing equivalent functionality. |
| 166 | + |
| 167 | +Rejected Alternatives |
| 168 | +********************* |
| 169 | +* **RBAC-only**: too limited for contextual decisions. |
| 170 | +* **ReBAC**: rejected because it adds complexity and we lack strong use cases today. |
| 171 | + - While ReBAC solves inheritance and recursive relationships well, it introduces complexity and a different way of thinking about authorization. |
| 172 | +* **In-code checks**: not auditable or shareable. |
| 173 | +* **Custom-built engine**: unnecessary when proven frameworks exist. |
| 174 | + |
| 175 | +References |
| 176 | +********** |
| 177 | +WIP |
| 178 | + |
| 179 | +Glossary |
| 180 | +******** |
| 181 | +* **Policy**: A declarative rule that defines which subjects can perform which actions on which objects under which context. Policies are stored outside of code, versioned, and auditable. |
| 182 | + |
| 183 | +* **RBAC (Role-Based Access Control)**: Authorization model where access is granted based on roles assigned to users. |
| 184 | + |
| 185 | +* **Scoped RBAC**: A variant of RBAC where roles apply within a specific scope (e.g., organization, course, library). |
| 186 | + |
| 187 | +* **ABAC (Attribute-Based Access Control)**: Authorization model where access is granted based on attributes of the subject, object, and context (e.g., user's organization, resource type, time of day). |
| 188 | + |
| 189 | +* **ReBAC (Relationship-Based Access Control)**: Authorization model where access decisions are based on explicit relationships between subjects and objects, often modeled as a graph. |
| 190 | + |
| 191 | +* **S-A-O-C (Subject-Action-Object-Context)**: The canonical shape of any authorization check: *is Subject allowed to perform Action on Object under Context?* |
| 192 | + |
| 193 | +* **Authorization check**: The explicit way a service asks whether an operation is allowed, always expressed in S-A-O-C form. |
| 194 | + |
| 195 | +* **Query check**: A pattern where the system returns all objects of type X on which a subject can perform a given action, under a given context. |
0 commit comments