Skip to content

Commit 9583a0b

Browse files
Merge branch 'main' into jd/validate-users
2 parents bb4c3c6 + ef8b1d1 commit 9583a0b

2 files changed

Lines changed: 169 additions & 0 deletions

File tree

CHANGELOG.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Added
2222

2323
* Add ``GlobalPermission`` class for cross-scope permission checking without requiring specific scope parameters.
2424
* Add ``users/`` endpoint endpoint for bulk validation of user identifiers (usernames or emails).
25+
* Add ADR for global scope support for role assignments.
2526

2627
1.2.0 - 2026-03-30
2728
******************
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
0012: Glob Support For Role Assignments
2+
#######################################
3+
4+
Status
5+
******
6+
7+
**Draft** - *2026-03-18*
8+
9+
Context
10+
*******
11+
12+
The current authorization system is based on Casbin and models:
13+
14+
- **Permissions per role** (``p`` policies), where the ``scope`` field may already include the existing namespace wildcard ``^*`` (for example, ``lib^*`` meaning "any scope in the ``lib`` namespace").
15+
- **Role assignments** (``g`` policies), which link a subject to a role within a scope.
16+
17+
The current Casbin model treats the ``scope`` field in ``g`` policies as an **exact match**. This is sufficient when roles are granted for a single, concrete scope value, but it is limiting when operators need to:
18+
19+
- Assign roles that are valid for a **set of resources** that share a common prefix (for example, all courses or all content libraries belonging to a given organization).
20+
- Avoid enumerating a large or evolving set of resources one by one, which increases operational overhead and risk of drift.
21+
22+
This ADR proposes enabling glob-like matching for role assignments, so that a single ``g`` policy can represent a multi-scope assignment such as:
23+
24+
.. code:: text
25+
26+
g, user^contributor, role^course_staff, course-v1^course-v1:OpenedX+*
27+
28+
In that example, checking a permission such as:
29+
30+
.. code:: text
31+
32+
authz_api.is_user_allowed("contributor", "courses.manage_advanced_settings", "course-v1:OpenedX+Some+Course")
33+
34+
should be allowed if the user's role assignment matches the ``course-v1:OpenedX+*`` pattern.
35+
36+
At the same time, we must preserve the guarantees of the authorization model:
37+
38+
- **Safety**: Glob patterns must not accidentally grant permissions outside the intended identifier boundary.
39+
- **Clarity**: Patterns must be easy to understand and reason about for operators and auditors.
40+
- **Extensibility**: The mechanism should be general enough to support future use cases without requiring a redesign of the model.
41+
42+
Decision
43+
********
44+
45+
We will introduce support for glob-like matching on the ``scope`` field of **role assignments** (``g`` policies), combined with explicit validation in the public APIs that manage those assignments.
46+
47+
The decision is intentionally **general**: the core change is to allow glob matching for scopes in ``g`` policies, and to guard its usage with well-defined, namespace-specific validation rules. This creates a foundation that can be extended later without changing the Casbin model again.
48+
49+
1. Enable glob matching on ``g`` scopes in the enforcer
50+
=======================================================
51+
52+
We will configure the ``AuthzEnforcer`` to use a domain/scope matching function for ``g`` policies that supports glob-like suffixes. Concretely:
53+
54+
- The enforcer will register a domain matching function for the ``g`` (grouping) function (for example, using ``key_match_func``).
55+
- This matching function will treat ``*`` as a wildcard at the **end** of the string (suffix wildcard). That is, patterns such as ``course-v1:OpenedX+*`` will match ``course-v1:OpenedX+SOME+COURSE``, but the model will not rely on complex patterns or regular expressions.
56+
- Matching is **case-sensitive**. Scope comparisons follow exact string semantics for non-wildcard characters (for example, ``course-v1:openedx+*`` does not match ``course-v1:OpenedX+...``).
57+
- Existing ``g`` policies that use exact scopes remain valid and continue to behave identically. They follow the same validation path as before. Only scopes containing a ``*`` suffix glob take a different API-side validation path.
58+
59+
This change allows the Casbin engine to evaluate role assignments that apply to a family of scopes instead of a single exact value, without modifying the underlying storage schema (``CasbinRule``) or the overall request format (``r = sub, act, scope``).
60+
61+
2. Validate glob scopes at the API boundary
62+
===========================================
63+
64+
All APIs that create, update, or delete role assignments (i.e., policies of type ``g``) must validate any scope that includes a glob pattern. The goals of validation are:
65+
66+
- **Constrain** what forms of glob are permitted for each namespace.
67+
- **Reject** malformed or overly broad patterns that would be difficult to reason about or audit.
68+
69+
The following rules apply initially:
70+
71+
- The glob character (``*``) is only supported as a **suffix wildcard**. It cannot appear in the middle of a scope identifier.
72+
- A glob pattern represents a **boundary-constrained prefix match** for the external key portion of a scope within its namespace. In practice, this means matching is limited to a well-defined identifier boundary, and the glob cannot be used to create overly broad or unsafe matches.
73+
- For any glob patterns (courses, libraries, or future namespaces), malformed inputs (such as mid-string wildcards or prefixes that do not match expected key formats or identifier boundaries) are **rejected**.
74+
- Additional namespaces must define their own, explicit validation rules before accepting glob scopes. If a namespace does not have a custom matcher/validator, any ``*`` in its scope is rejected and only exact scopes are accepted.
75+
- As needs evolve, more glob pattern types can be added safely by introducing namespace-specific semantics and validations (for example, additional prefix boundaries such as program/tenant prefixes, or narrower matching strategies if required).
76+
77+
Examples of valid/invalid namespace scope globs
78+
-----------------------------------------------
79+
80+
Given the current suffix-glob policy (single trailing ``*`` at a namespace-approved boundary):
81+
82+
- Invalid: ``*`` (unbounded across all namespaces/scopes).
83+
- Invalid: ``c*`` or ``l*`` (not a valid namespaced scope prefix).
84+
- Invalid: ``course-v1*`` or ``lib*`` (missing ``:`` and required namespace structure).
85+
- Invalid: ``course-v1:*`` or ``lib:*`` (wildcard starts before a valid prefix boundary inside the ``course-v1`` or ``lib`` key).
86+
- Invalid: ``course-v1:O*`` or ``lib:MIT*`` (wildcard starts mid-segment. Prefix boundary is not complete).
87+
- Valid: ``course-v1:OpenedX+*`` (wildcard starts at an approved boundary for the ``course-v1`` namespace).
88+
- Valid: ``lib:MITx:*`` (wildcard starts at an approved boundary for the ``lib`` namespace).
89+
90+
These validation rules are implemented in the Open edX layer (API / data layer), not in the Casbin matcher itself. The enforcer remains general-purpose. The domain-specific semantics of what constitutes an acceptable glob pattern are enforced at the boundary where user/operator input is turned into policies.
91+
92+
3. Keep the model general and extensible
93+
========================================
94+
95+
By introducing glob support in role assignments in a boundary-constrained way, we unlock a set of future extensions without redesigning the model:
96+
97+
- **Other scope types**
98+
99+
- Scope types with hierarchical or prefix-based identifiers (for example, libraries or other content groupings) can adopt glob pattern support by:
100+
101+
- Defining their own namespace-specific rules for valid suffix globs.
102+
- Reusing the same enforcer-level domain matching capability.
103+
104+
- **Future matching strategies**
105+
106+
- If, in the future, there is a strong need for more expressive matching (for example, segment-based matching or multiple wildcards), these can be introduced as **new, explicitly-scoped features** with their own validation rules and migration story.
107+
- For now, we deliberately keep glob support simple and limited (single trailing ``*``) to minimize complexity and security risk.
108+
109+
Consequences
110+
************
111+
112+
Positive consequences
113+
=====================
114+
115+
- **Increased expressiveness**: Operators can express multi-scope role assignments (for example, "course staff for all courses in organization OpenedX") without enumerating each course in individual ``g`` policies.
116+
- **Reduced operational overhead**: New resources that fall under an existing glob pattern automatically inherit the appropriate role assignments, reducing the need for ongoing manual updates.
117+
- **Better alignment with real-world use cases**: Many organizational setups naturally require "all resources under this prefix" semantics. Glob pattern support maps directly to those needs.
118+
- **Clear extension path**: The mechanism is generic enough to be reused for other namespaces (such as organization or library scopes), as long as each namespace defines and enforces its own validation rules.
119+
120+
Negative consequences / risks
121+
=============================
122+
123+
- **Security and safety**: If validation is misconfigured or bypassed, glob patterns could unintentionally grant access beyond the intended identifier boundary. This risk is mitigated by:
124+
125+
- Enforcing validation in the Open edX API layer.
126+
- Restricting globs to trailing ``*`` patterns.
127+
- Defining precise, namespace-specific rules.
128+
129+
- **Complexity in mental model**: Operators and developers must understand that some role assignments apply to families of scopes instead of a single scope. This can be addressed by:
130+
131+
- Providing clear documentation and examples for glob-based assignments.
132+
- Exposing introspection tooling that explains which policies matched a given decision.
133+
134+
- **Performance considerations**: Glob matching adds some overhead to Casbin evaluations. However:
135+
136+
- The cost of simple suffix matching is low.
137+
- The policy store still uses the same schema and indexing strategy.
138+
- The feature should be used primarily for coarse-grained groupings (e.g., by organization), not for highly fragmented patterns.
139+
140+
Rejected Alternatives
141+
**********************
142+
143+
- **Keep exact matching only for 'g' scopes**
144+
145+
- Pros:
146+
147+
- Simpler to reason about.
148+
- No changes to matcher configuration.
149+
- Cons:
150+
151+
- Does not scale for environments with many resources per organization.
152+
- Forces operators to maintain large numbers of nearly-identical assignments.
153+
154+
- **Introduce full regular-expression support on scopes**
155+
156+
- Pros:
157+
158+
- Maximum flexibility for expressing patterns.
159+
- Cons:
160+
161+
- Harder to reason about and audit.
162+
- Higher risk of misconfiguration and security overshoot.
163+
- Potentially worse performance.
164+
165+
References
166+
**********
167+
168+
- `Casbin function documentation (matching functions) <https://casbin.org/docs/function/>`_

0 commit comments

Comments
 (0)