Skip to content

Commit ca26e5e

Browse files
refactor: place roles, permissions and user functions into their own modules
1 parent 18232a3 commit ca26e5e

14 files changed

Lines changed: 1712 additions & 230 deletions

File tree

openedx_authz/api/__init__.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
provide a simpler interface for other services in the Open edX ecosystem.
66
"""
77

8-
# from openedx_authz.api.roles import create_role
9-
# from openedx_authz.api.permissions import create_permission
10-
# from openedx_authz.api.policy import create_policy
11-
12-
# __all__ = ["create_role", "create_permission", "create_policy"]
8+
from openedx_authz.api.data import *
9+
from openedx_authz.api.permissions import *
10+
from openedx_authz.api.roles import *
11+
from openedx_authz.api.users import *

openedx_authz/api/data.py

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
"""Data classes and enums for representing roles, permissions, and policies."""
2+
3+
from enum import Enum
4+
from typing import Literal
5+
6+
from attrs import define
7+
8+
9+
class GroupingPolicyIndex(Enum):
10+
"""Index of fields in a grouping policy."""
11+
12+
SUBJECT = 0
13+
ROLE = 1
14+
SCOPE = 2
15+
# The rest of the fields are optional and can be ignored for now
16+
17+
18+
class PolicyIndex(Enum):
19+
"""Index of fields in a policy."""
20+
21+
ROLE = 0
22+
ACT = 1
23+
SCOPE = 2
24+
EFFECT = 3
25+
# The rest of the fields are optional and can be ignored for now
26+
27+
28+
@define
29+
class Permission: # TODO: change to policy?
30+
"""A permission is an action that can be performed under certain conditions.
31+
32+
Attributes:
33+
name: The name of the permission.
34+
"""
35+
36+
# TODO: what other attributes should a permission have?
37+
name: str
38+
effect: Literal["allow", "deny"] = "allow"
39+
40+
41+
@define
42+
class RoleMetadata:
43+
"""Metadata for a role.
44+
45+
Attributes:
46+
description: A description of the role.
47+
created_at: The date and time the role was created.
48+
created_by: The ID of the subject who created the role.
49+
"""
50+
51+
description: str = None
52+
created_at: str = None
53+
created_by: str = None
54+
55+
56+
@define
57+
class Role:
58+
"""A role is a named group of permissions.
59+
60+
Attributes:
61+
name: The name of the role.
62+
permissions: A list of permissions assigned to the role.
63+
scopes: A list of scopes assigned to the role.
64+
metadata: A dictionary of metadata assigned to the role. This can include
65+
information such as the description of the role, creation date, etc.
66+
"""
67+
68+
name: str
69+
scopes: list[str]
70+
permissions: list[Permission] = None
71+
metadata: RoleMetadata = None
72+
73+
74+
@define
75+
class RoleAssignment:
76+
"""A role assignment is the assignment of a role to a subject in a specific scope.
77+
78+
Attributes:
79+
subject: The ID of the user namespaced (e.g., 'user:john_doe').
80+
email: The email of the user.
81+
role_name: The name of the role.
82+
scope: The scope in which the role is assigned.
83+
"""
84+
85+
subject: str # TODO: I think here it makes sense to sanitize the subject so it's the username?
86+
role: Role

openedx_authz/api/permissions.py

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,39 @@
55
are not explicitly defined, but are inferred from the policy rules.
66
"""
77

8+
from typing import Literal
89

9-
def has_permission(user: str, resource: str, action: str, scope: str = None) -> bool:
10-
"""Check if a user has a specific permission.
10+
from openedx_authz.api.data import Permission, PolicyIndex
11+
from openedx_authz.engine.enforcer import enforcer
12+
13+
__all__ = ["get_permission_from_policy", "get_all_permissions_in_scope"]
14+
15+
16+
def get_permission_from_policy(policy: list[str]) -> Permission:
17+
"""Convert a Casbin policy list to a Permission object.
1118
1219
Args:
13-
user: The user to check.
14-
resource: The resource to check.
15-
action: The action to check.
16-
scope: The scope to check (optional).
20+
policy: A list representing a Casbin policy.
21+
22+
Returns:
23+
Permission: The corresponding Permission object or an empty Permission if the policy is invalid.
24+
"""
25+
if len(policy) < 4: # Do not count ptype
26+
return Permission(name="", effect="")
27+
28+
return Permission(
29+
name=policy[PolicyIndex.ACT.value], effect=policy[PolicyIndex.EFFECT.value]
30+
)
31+
32+
33+
def get_all_permissions_in_scope(scope: str) -> list[Permission]:
34+
"""Retrieve all permissions associated with a specific scope.
35+
36+
Args:
37+
scope: The scope to filter permissions by.
38+
39+
Returns:
40+
list of Permission: A list of Permission objects associated with the given scope.
1741
"""
42+
actions = enforcer.get_filtered_policy(PolicyIndex.SCOPE.value, scope)
43+
return [get_permission_from_policy(action) for action in actions]

openedx_authz/api/policy.py

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)