Browse Source
Added a hierarchical Role system and lookup for the authentication.
merge-requests/1/head
Added a hierarchical Role system and lookup for the authentication.
merge-requests/1/head
8 changed files with 126 additions and 13 deletions
-
BINserver/.admin_credentials.swp
-
3server/atheneum/api/user_api.py
-
7server/atheneum/middleware/authentication_middleware.py
-
7server/atheneum/model/user_model.py
-
88server/atheneum/service/role_service.py
-
7server/atheneum/service/user_service.py
-
8server/tests/api/test_user_api.py
-
19server/tests/service/test_role_service.py
@ -0,0 +1,88 @@ |
|||||
|
"""Role service for Atheneum.""" |
||||
|
from collections import defaultdict |
||||
|
from enum import Enum |
||||
|
from typing import Optional, List, Set, Dict |
||||
|
|
||||
|
|
||||
|
class Role(Enum): |
||||
|
"""User role definitions.""" |
||||
|
|
||||
|
ADMIN = 'ADMIN' |
||||
|
AUDITOR = 'AUDITOR' |
||||
|
MODERATOR = 'MODERATOR' |
||||
|
USER = 'USER' |
||||
|
ANONYMOUS = 'ANONYMOUS' |
||||
|
NONE = 'NONE' |
||||
|
|
||||
|
|
||||
|
class RoleTree(defaultdict): |
||||
|
"""Simple tree structure to handle hierarchy.""" |
||||
|
|
||||
|
def __call__(self, data: Role) -> 'RoleTree': |
||||
|
"""Handle direct calls to the tree.""" |
||||
|
return RoleTree(self, data) |
||||
|
|
||||
|
# def __hash__(self): |
||||
|
|
||||
|
def __init__( |
||||
|
self, |
||||
|
parent: Optional['RoleTree'], |
||||
|
data: Role, |
||||
|
**kwargs: dict) -> None: |
||||
|
"""Configure a RoleTree.""" |
||||
|
super().__init__(**kwargs) |
||||
|
self.parent: Optional[RoleTree] = parent |
||||
|
self.data: Role = data |
||||
|
self.default_factory = self # type: ignore |
||||
|
self.roles: Dict[Role, List[RoleTree]] = {data: [self]} |
||||
|
|
||||
|
def populate( |
||||
|
self, children: Dict[Role, Optional[dict]]) -> List['RoleTree']: |
||||
|
"""Populate a RoleTree from a dictionary of a Role hierarchy.""" |
||||
|
role_list: List[RoleTree] = [] |
||||
|
for child_role in children.keys(): |
||||
|
element = children[child_role] |
||||
|
new_node = self(child_role) |
||||
|
if isinstance(element, dict) and element: |
||||
|
role_list += new_node.populate(element) |
||||
|
self[child_role] = new_node |
||||
|
role_list.append(new_node) |
||||
|
for role_tree in role_list: |
||||
|
if role_tree.data not in self.roles.keys(): |
||||
|
self.roles[role_tree.data] = [] |
||||
|
self.roles[role_tree.data].append(role_tree) |
||||
|
return role_list |
||||
|
|
||||
|
def find_role(self, request_role: Role) -> List['RoleTree']: |
||||
|
"""Identify all instances of a role.""" |
||||
|
try: |
||||
|
return [role_tree for role_tree in self.roles[request_role]] |
||||
|
except KeyError: |
||||
|
return [] |
||||
|
|
||||
|
def get_parent_roles(self) -> List[Role]: |
||||
|
"""Return all the roles from self to the highest parent.""" |
||||
|
if self.parent is not None: |
||||
|
return [self.data] + self.parent.get_parent_roles() |
||||
|
return [self.data] |
||||
|
|
||||
|
def find_roles_in_hierarchy(self, request_role: Role) -> Set[Role]: |
||||
|
"""Find a set of all roles that fall within the hierarchy.""" |
||||
|
roles: List[Role] = [] |
||||
|
role_trees = self.find_role(request_role) |
||||
|
for role_tree in role_trees: |
||||
|
roles.extend(role_tree.get_parent_roles()) |
||||
|
return set(role for role in roles) |
||||
|
|
||||
|
|
||||
|
ROLES = RoleTree(None, Role.ADMIN) |
||||
|
ROLES.populate({ |
||||
|
Role.MODERATOR: { |
||||
|
Role.USER: { |
||||
|
Role.ANONYMOUS: None |
||||
|
} |
||||
|
}, |
||||
|
Role.AUDITOR: { |
||||
|
Role.USER: None |
||||
|
} |
||||
|
}) |
@ -0,0 +1,19 @@ |
|||||
|
from atheneum.service.role_service import ROLES, Role |
||||
|
|
||||
|
|
||||
|
def test_role_tree_find_roles_in_hierarchy(): |
||||
|
roles = ROLES.find_roles_in_hierarchy(Role.USER) |
||||
|
assert len(roles) == 4 |
||||
|
assert Role.USER in roles |
||||
|
assert Role.MODERATOR in roles |
||||
|
assert Role.AUDITOR in roles |
||||
|
assert Role.ADMIN in roles |
||||
|
|
||||
|
roles = ROLES.find_roles_in_hierarchy(Role.AUDITOR) |
||||
|
assert len(roles) == 2 |
||||
|
assert Role.AUDITOR in roles |
||||
|
assert Role.ADMIN in roles |
||||
|
|
||||
|
|
||||
|
def test_role_tree_find_role_key_error(): |
||||
|
assert len(ROLES.find_role(Role.NONE)) == 0 |
Write
Preview
Loading…
Cancel
Save
Reference in new issue