forked from openedx/openedx-authz
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmodel.conf
More file actions
92 lines (86 loc) · 3.89 KB
/
model.conf
File metadata and controls
92 lines (86 loc) · 3.89 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
############################################
# Open edX AuthZ — Casbin Model Configuration
#
# 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 (course:*, lib:*, org:*, etc.)
# - Extensibility (new resource types just need new namespaces)
############################################
[request_definition]
# Request format: subject (user), action, scope (specific resource being accessed)
#
# sub = subject/principal with namespace (e.g., "user:alice", "service:lms")
# act = action with namespace (e.g., "act:read", "act:manage", "act:edit-courses")
# scope = authorization scope context (e.g., "org:OpenedX", "course-v1:...", "*" for global)
#
# SCOPE SEMANTICS:
# Scope determines the authorization context and which role assignments apply
# - "*" = global scope (system-wide roles apply everywhere)
# - "org:..." = organization-scoped roles (apply within specific organization)
# - "course-v1:..." = course-scoped roles (apply within specific course)
# - "lib:..." = library-scoped roles (apply within specific library)
#
# Application must provide appropriate scope based on business logic.
r = sub, act, scope
[policy_definition]
# Policy format: subject (role), action, scope (pattern), effect
#
# sub = role or user with namespace (e.g., "role:org_admin", "user:bob")
# act = action identifier (e.g., "act:manage", "act:read", "act:edit-courses")
# scope = scope where policy applies (e.g., "*", "org:*", "course-v1:*", "lib:*")
# eft = "allow" or "deny" (deny overrides allow for exceptions)
p = sub, act, scope, eft
[role_definition]
# g: Role assignments with scope
# Format: user/subject, role, scope
#
# Examples:
# g, user:alice, role:org_admin, org:OpenedX # Alice is org admin for OpenedX
# g, user:bob, role:course_instructor, course-v1:... # Bob is instructor for specific course
# g, user:carol, role:library_admin, * # Carol is global library admin
#
# Role hierarchy (optional):
# 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")
#
# Evaluation order:
# 1. Check if any policy grants allow
# 2. Check if any policy specifies deny
# 3. If deny found, result is deny (exceptions win)
# 4. If allow found and no deny, result is allow
# 5. If no matches, result is deny (default secure)
e = some(where (p.eft == allow)) && !some(where (p.eft == deny))
[matchers]
# Authorization matching logic
#
# ROLE MATCHING:
# - g(r.sub, p.sub, r.scope): check if subject has role in requested scope
# - g(r.sub, p.sub, "*"): check if subject has role in all resources in the scope
#
# 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 = (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))