@@ -26,20 +26,80 @@ class PolicyIndex(Enum):
2626
2727
2828@define
29- class Permission : # TODO: change to policy?
29+ class UserData :
30+ """A user is a subject that can be assigned roles and permissions.
31+
32+ Attributes:
33+ username: The username. Automatically prefixed with 'user:' if not present.
34+ """
35+
36+ username : str
37+
38+ def __attrs_post_init__ (self ):
39+ """Ensure username has 'user:' namespace prefix."""
40+ if not self .username .startswith ("user:" ):
41+ object .__setattr__ (self , "username" , f"user:{ self .username } " )
42+
43+
44+ @define
45+ class ScopeData :
46+ """A scope is a context in which roles and permissions are assigned.
47+
48+ Attributes:
49+ scope_id: The scope identifier (e.g., 'course-v1:edX+DemoX+2021_T1').
50+
51+ This class assumes that the scope is already namespaced appropriately
52+ before being passed in, as scopes can vary widely (e.g., courses, organizations).
53+ """
54+
55+ scope_id : str
56+
57+
58+ @define
59+ class SubjectData :
60+ """A subject is an entity that can be assigned roles and permissions.
61+
62+ Attributes:
63+ subject_id: The subject identifier namespaced (e.g., 'user:john_doe').
64+
65+ This class assumes that the subject was already namespaced by their own
66+ type (e.g., 'user:', 'group:') before being passed in since subjects can be
67+ users, groups, or other entities.
68+ """
69+
70+ subject_id : str
71+
72+
73+ @define
74+ class ActionData :
75+ """An action is an operation that can be performed in a specific scope.
76+
77+ Attributes:
78+ action: The action name. Automatically prefixed with 'act:' if not present.
79+ """
80+
81+ action_id : str
82+
83+ def __attrs_post_init__ (self ):
84+ """Ensure action name has 'act:' namespace prefix."""
85+ if not self .action_id .startswith ("act:" ):
86+ object .__setattr__ (self , "action_id" , f"act:{ self .action_id } " )
87+
88+
89+ @define
90+ class PermissionData : # TODO: change to policy?
3091 """A permission is an action that can be performed under certain conditions.
3192
3293 Attributes:
3394 name: The name of the permission.
3495 """
3596
36- # TODO: what other attributes should a permission have?
37- name : str
97+ action : ActionData
3898 effect : Literal ["allow" , "deny" ] = "allow"
3999
40100
41101@define
42- class RoleMetadata :
102+ class RoleMetadataData :
43103 """Metadata for a role.
44104
45105 Attributes:
@@ -54,25 +114,29 @@ class RoleMetadata:
54114
55115
56116@define
57- class Role :
117+ class RoleData :
58118 """A role is a named group of permissions.
59119
60120 Attributes:
61- name: The name of the role.
121+ name: The name of the role. Must have 'role:' namespace prefix.
62122 permissions: A list of permissions assigned to the role.
63123 scopes: A list of scopes assigned to the role.
64124 metadata: A dictionary of metadata assigned to the role. This can include
65125 information such as the description of the role, creation date, etc.
66126 """
67127
68128 name : str
69- scopes : list [str ]
70- permissions : list [Permission ] = None
71- metadata : RoleMetadata = None
129+ permissions : list [PermissionData ] = None
130+ metadata : RoleMetadataData = None
131+
132+ def __attrs_post_init__ (self ):
133+ """Ensure role name has 'role:' namespace prefix."""
134+ if not self .name .startswith ("role:" ):
135+ object .__setattr__ (self , "name" , f"role:{ self .name } " )
72136
73137
74138@define
75- class RoleAssignment :
139+ class RoleAssignmentData :
76140 """A role assignment is the assignment of a role to a subject in a specific scope.
77141
78142 Attributes:
@@ -82,5 +146,6 @@ class RoleAssignment:
82146 scope: The scope in which the role is assigned.
83147 """
84148
85- subject : str # TODO: I think here it makes sense to sanitize the subject so it's the username?
86- role : Role
149+ subject : UserData
150+ role : RoleData
151+ scope : ScopeData
0 commit comments