Skip to content

Commit 2c78e0e

Browse files
committed
refactor: update model.conf
1 parent d43d0f2 commit 2c78e0e

1 file changed

Lines changed: 28 additions & 54 deletions

File tree

openedx_authz/engine/config/model.conf

Lines changed: 28 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,69 +3,50 @@
33
#
44
# This model supports:
55
# - Scoped role assignments (user roles tied to specific contexts)
6-
# - Action grouping (manage → read/write/delete to reduce duplication)
6+
# - Action grouping (manage → read/write/edit/delete to reduce duplication)
77
# - System-wide roles (global scope "*" applies everywhere)
8-
# - Scope-based permissions (authorization based on context, not specific objects)
98
# - Negative rules (deny overrides allow for exceptions)
10-
# - Namespace support (course-v1:*, lib:*, org:*, etc.)
11-
# - Extensibility (new resource types only require new scope namespaces)
12-
#
13-
# DESIGN PRINCIPLE:
14-
# - Authorization is scope-based, not object-based
15-
# - Each request is explicitly scoped (course, org, global, etc.)
16-
# - Permissions are granted within scopes, eliminating need for object matching
17-
# - Containment relationships are handled by the application layer
18-
#
19-
# NOT handled here (deferred to application):
20-
# - Resource grouping/containment (app resolves parent-child relationships)
21-
# - Role inheritance across scopes (app checks multiple scopes explicitly)
22-
# - Object lifecycle consistency (app handles cleanup on delete)
9+
# - Namespace support (course:*, lib:*, org:*, etc.)
10+
# - Extensibility (new resource types just need new namespaces)
2311
############################################
2412

2513
[request_definition]
26-
# Request format: subject, action, scope
14+
# Request format: subject (user), action, scope (specific resource being accessed)
2715
#
2816
# sub = subject/principal with namespace (e.g., "user:alice", "service:lms")
2917
# act = action with namespace (e.g., "act:read", "act:manage", "act:edit-courses")
3018
# scope = authorization scope context (e.g., "org:OpenedX", "course-v1:...", "*" for global)
3119
#
3220
# SCOPE SEMANTICS:
33-
# - Scope determines the authorization context and which role assignments apply
34-
# - "*" = global scope (system-wide roles apply everywhere)
35-
# - "org:OpenedX" = organization-scoped roles (apply within OpenedX org)
21+
# Scope determines the authorization context and which role assignments apply
22+
# - "*" = global scope (system-wide roles apply everywhere)
23+
# - "org:OpenedX" = organization-scoped roles (apply within OpenedX org)
3624
# - "course-v1:..." = course-scoped roles (apply within specific course)
3725
#
3826
# Application must provide appropriate scope based on business logic.
3927
r = sub, act, scope
4028

4129
[policy_definition]
42-
# Policy format: subject, action, scope, effect
30+
# Policy format: subject (role), action, scope (pattern), effect
4331
#
4432
# sub = role or user with namespace (e.g., "role:org_admin", "user:bob")
45-
# act = action identifier (e.g., "act:manage", "act:read", "act:edit-courses"). Uses g2 relation for action grouping.
46-
# scope = scope where policy applies (e.g., "*", "org:OpenedX", "course-v1:...")
33+
# act = action identifier (e.g., "act:manage", "act:read", "act:edit-courses")
34+
# scope = scope where policy applies (e.g., "*", "org:*", "course-v1:*", "lib:*")
4735
# eft = "allow" or "deny" (deny overrides allow for exceptions)
4836
p = sub, act, scope, eft
4937

5038
[role_definition]
51-
# g: Role assignments (without scope)
52-
# Format: user/subject, role
53-
#
54-
# This is a simplified role assignment where users are assigned roles globally,
55-
# without being tied to specific scopes. All role assignments apply system-wide.
39+
# g: Role assignments with scope
40+
# Format: user/subject, role, scope
5641
#
5742
# Examples:
58-
# g, user:alice, role:org_admin # Alice is org admin
59-
# g, user:bob, role:course_instructor # Bob is course instructor
60-
# g, user:carol, role:platform_admin # Carol is platform admin
61-
# g, service:lms, role:system_service # LMS service has system-wide access
43+
# g, user:alice, role:org_admin, org:OpenedX # Alice is org admin for OpenedX
44+
# g, user:bob, role:course_instructor, course-v1:... # Bob is instructor for specific course
45+
# g, user:carol, role:library_admin, * # Carol is global library admin
6246
#
6347
# Role hierarchy (optional):
64-
# g, role:org_admin, role:org_editor # org_admin inherits org_editor permissions
65-
#
66-
# NOTE: Without scope in role assignments, authorization control must rely entirely
67-
# on policy definitions (p) to restrict access to appropriate scopes/contexts.
68-
g = _, _
48+
# g, role:org_admin, role:org_editor, org:OpenedX # org_admin inherits org_editor permissions
49+
g = _, _, _
6950

7051
# g2: Action grouping and implications
7152
# Maps high-level actions to specific actions to reduce policy duplication
@@ -92,26 +73,19 @@ e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
9273
[matchers]
9374
# Authorization matching logic
9475
#
95-
# SUBJECT MATCHING:
96-
# - g(r.sub, p.sub): check if request subject matches policy subject (role assignment)
97-
# This handles user-to-role mappings defined in the role_definition section
76+
# ROLE MATCHING:
77+
# - g(r.sub, p.sub, r.scope): check if subject has role in requested scope
78+
# - g(r.sub, p.sub, "*"): check if subject has role in all resources in the scope
79+
#
80+
# SCOPE MATCHING:
81+
# - keyMatch(r.scope, p.scope): scope matches pattern
9882
#
9983
# ACTION MATCHING:
84+
# - r.act == p.act: exact action match
10085
# - g2(p.act, r.act): policy action implies requested action via grouping
101-
# Allows high-level actions (manage) to grant specific actions (read/write/delete)
102-
#
103-
# SCOPE MATCHING:
104-
# - keyMatch(r.scope, p.scope): check if request scope matches policy scope
105-
# Supports wildcard matching (e.g., "*" matches any scope)
106-
# Enables hierarchical scope matching for nested authorization contexts
10786
#
10887
# All conditions must be true for a policy to match:
109-
# 1. Subject must have the required role (via role assignment)
110-
# 2. Policy action must imply the requested action (via action grouping)
111-
# 3. Request scope must match the policy scope (with wildcard support)
112-
#
113-
# SCOPE-BASED AUTHORIZATION:
114-
# The matcher uses keyMatch for flexible scope matching, allowing policies
115-
# to apply to specific scopes (org:OpenedX) or globally (*), providing
116-
# fine-grained control over authorization contexts.
117-
m = g(r.sub, p.sub) && g2(p.act, r.act) && keyMatch(r.scope, p.scope)
88+
# 1. Subject must have role in scope OR global role
89+
# 2. Scope must match pattern
90+
# 3. Action must match OR inherit via action grouping
91+
m = (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))

0 commit comments

Comments
 (0)