moved remove permission code to own method and some cleanup

This commit is contained in:
jasquat 2023-05-18 12:35:23 -04:00
parent 40b3246eb7
commit a445badcd1
1 changed files with 36 additions and 42 deletions

View File

@ -1,4 +1,3 @@
"""Authorization_service."""
import inspect import inspect
import re import re
from dataclasses import dataclass from dataclasses import dataclass
@ -40,25 +39,23 @@ from spiffworkflow_backend.services.user_service import UserService
class PermissionsFileNotSetError(Exception): class PermissionsFileNotSetError(Exception):
"""PermissionsFileNotSetError.""" pass
class HumanTaskNotFoundError(Exception): class HumanTaskNotFoundError(Exception):
"""HumanTaskNotFoundError.""" pass
class UserDoesNotHaveAccessToTaskError(Exception): class UserDoesNotHaveAccessToTaskError(Exception):
"""UserDoesNotHaveAccessToTaskError.""" pass
class InvalidPermissionError(Exception): class InvalidPermissionError(Exception):
"""InvalidPermissionError.""" pass
@dataclass @dataclass
class PermissionToAssign: class PermissionToAssign:
"""PermissionToAssign."""
permission: str permission: str
target_uri: str target_uri: str
@ -91,7 +88,7 @@ class UserToGroupDict(TypedDict):
group_identifier: str group_identifier: str
class DesiredPermissionDict(TypedDict): class AddedPermissionDict(TypedDict):
group_identifiers: Set[str] group_identifiers: Set[str]
permission_assignments: list[PermissionAssignmentModel] permission_assignments: list[PermissionAssignmentModel]
user_to_group_identifiers: list[UserToGroupDict] user_to_group_identifiers: list[UserToGroupDict]
@ -114,7 +111,6 @@ class AuthorizationService:
# https://stackoverflow.com/a/71320673/6090676 # https://stackoverflow.com/a/71320673/6090676
@classmethod @classmethod
def verify_sha256_token(cls, auth_header: Optional[str]) -> None: def verify_sha256_token(cls, auth_header: Optional[str]) -> None:
"""Verify_sha256_token."""
if auth_header is None: if auth_header is None:
raise TokenNotProvidedError( raise TokenNotProvidedError(
"unauthorized", "unauthorized",
@ -130,7 +126,6 @@ class AuthorizationService:
@classmethod @classmethod
def has_permission(cls, principals: list[PrincipalModel], permission: str, target_uri: str) -> bool: def has_permission(cls, principals: list[PrincipalModel], permission: str, target_uri: str) -> bool:
"""Has_permission."""
principal_ids = [p.id for p in principals] principal_ids = [p.id for p in principals]
target_uri_normalized = target_uri.removeprefix(V1_API_PATH_PREFIX) target_uri_normalized = target_uri.removeprefix(V1_API_PATH_PREFIX)
@ -160,7 +155,6 @@ class AuthorizationService:
@classmethod @classmethod
def user_has_permission(cls, user: UserModel, permission: str, target_uri: str) -> bool: def user_has_permission(cls, user: UserModel, permission: str, target_uri: str) -> bool:
"""User_has_permission."""
if user.principal is None: if user.principal is None:
raise MissingPrincipalError(f"Missing principal for user with id: {user.id}") raise MissingPrincipalError(f"Missing principal for user with id: {user.id}")
@ -186,7 +180,6 @@ class AuthorizationService:
@classmethod @classmethod
def associate_user_with_group(cls, user: UserModel, group: GroupModel) -> None: def associate_user_with_group(cls, user: UserModel, group: GroupModel) -> None:
"""Associate_user_with_group."""
user_group_assignemnt = UserGroupAssignmentModel.query.filter_by(user_id=user.id, group_id=group.id).first() user_group_assignemnt = UserGroupAssignmentModel.query.filter_by(user_id=user.id, group_id=group.id).first()
if user_group_assignemnt is None: if user_group_assignemnt is None:
user_group_assignemnt = UserGroupAssignmentModel(user_id=user.id, group_id=group.id) user_group_assignemnt = UserGroupAssignmentModel(user_id=user.id, group_id=group.id)
@ -194,7 +187,7 @@ class AuthorizationService:
db.session.commit() db.session.commit()
@classmethod @classmethod
def import_permissions_from_yaml_file(cls, user_model: Optional[UserModel] = None) -> DesiredPermissionDict: def import_permissions_from_yaml_file(cls, user_model: Optional[UserModel] = None) -> AddedPermissionDict:
group_permissions = cls.parse_permissions_yaml_into_group_info() group_permissions = cls.parse_permissions_yaml_into_group_info()
result = cls.add_permissions_from_group_permissions(group_permissions, user_model) result = cls.add_permissions_from_group_permissions(group_permissions, user_model)
return result return result
@ -292,7 +285,6 @@ class AuthorizationService:
@classmethod @classmethod
def check_for_permission(cls) -> None: def check_for_permission(cls) -> None:
"""Check_for_permission."""
if cls.should_disable_auth_for_request(): if cls.should_disable_auth_for_request():
return None return None
@ -326,11 +318,6 @@ class AuthorizationService:
@staticmethod @staticmethod
def decode_auth_token(auth_token: str) -> dict[str, Union[str, None]]: def decode_auth_token(auth_token: str) -> dict[str, Union[str, None]]:
"""Decode the auth token.
:param auth_token:
:return: integer|string
"""
secret_key = current_app.config.get("SECRET_KEY") secret_key = current_app.config.get("SECRET_KEY")
if secret_key is None: if secret_key is None:
raise KeyError("we need current_app.config to have a SECRET_KEY") raise KeyError("we need current_app.config to have a SECRET_KEY")
@ -374,10 +361,11 @@ class AuthorizationService:
@classmethod @classmethod
def create_user_from_sign_in(cls, user_info: dict) -> UserModel: def create_user_from_sign_in(cls, user_info: dict) -> UserModel:
"""Create_user_from_sign_in.""" """Fields from user_info.
"""Name, family_name, given_name, middle_name, nickname, preferred_username,"""
"""Profile, picture, website, gender, birthdate, zoneinfo, locale, and updated_at. """ name, family_name, given_name, middle_name, nickname, preferred_username,
"""Email.""" profile, picture, website, gender, birthdate, zoneinfo, locale,updated_at, email.
"""
is_new_user = False is_new_user = False
user_attributes = {} user_attributes = {}
@ -450,7 +438,6 @@ class AuthorizationService:
process_related_path_segment: str, process_related_path_segment: str,
target_uris: list[str], target_uris: list[str],
) -> list[PermissionToAssign]: ) -> list[PermissionToAssign]:
"""Get_permissions_to_assign."""
permissions = permission_set.split(",") permissions = permission_set.split(",")
if permission_set == "all": if permission_set == "all":
permissions = ["create", "read", "update", "delete"] permissions = ["create", "read", "update", "delete"]
@ -500,7 +487,6 @@ class AuthorizationService:
@classmethod @classmethod
def set_basic_permissions(cls) -> list[PermissionToAssign]: def set_basic_permissions(cls) -> list[PermissionToAssign]:
"""Set_basic_permissions."""
permissions_to_assign: list[PermissionToAssign] = [] permissions_to_assign: list[PermissionToAssign] = []
permissions_to_assign.append(PermissionToAssign(permission="create", target_uri="/process-instances/for-me")) permissions_to_assign.append(PermissionToAssign(permission="create", target_uri="/process-instances/for-me"))
permissions_to_assign.append( permissions_to_assign.append(
@ -528,7 +514,6 @@ class AuthorizationService:
@classmethod @classmethod
def set_process_group_permissions(cls, target: str, permission_set: str) -> list[PermissionToAssign]: def set_process_group_permissions(cls, target: str, permission_set: str) -> list[PermissionToAssign]:
"""Set_process_group_permissions."""
permissions_to_assign: list[PermissionToAssign] = [] permissions_to_assign: list[PermissionToAssign] = []
process_group_identifier = target.removeprefix("PG:").replace("/", ":").removeprefix(":") process_group_identifier = target.removeprefix("PG:").replace("/", ":").removeprefix(":")
process_related_path_segment = f"{process_group_identifier}:*" process_related_path_segment = f"{process_group_identifier}:*"
@ -545,7 +530,6 @@ class AuthorizationService:
@classmethod @classmethod
def set_process_model_permissions(cls, target: str, permission_set: str) -> list[PermissionToAssign]: def set_process_model_permissions(cls, target: str, permission_set: str) -> list[PermissionToAssign]:
"""Set_process_model_permissions."""
permissions_to_assign: list[PermissionToAssign] = [] permissions_to_assign: list[PermissionToAssign] = []
process_model_identifier = target.removeprefix("PM:").replace("/", ":").removeprefix(":") process_model_identifier = target.removeprefix("PM:").replace("/", ":").removeprefix(":")
process_related_path_segment = f"{process_model_identifier}/*" process_related_path_segment = f"{process_model_identifier}/*"
@ -668,7 +652,7 @@ class AuthorizationService:
@classmethod @classmethod
def add_permissions_from_group_permissions( def add_permissions_from_group_permissions(
cls, group_permissions: list[GroupPermissionsDict], user_model: Optional[UserModel] = None cls, group_permissions: list[GroupPermissionsDict], user_model: Optional[UserModel] = None
) -> DesiredPermissionDict: ) -> AddedPermissionDict:
unique_user_group_identifiers: Set[str] = set() unique_user_group_identifiers: Set[str] = set()
user_to_group_identifiers: list[UserToGroupDict] = [] user_to_group_identifiers: list[UserToGroupDict] = []
permission_assignments = [] permission_assignments = []
@ -715,19 +699,18 @@ class AuthorizationService:
} }
@classmethod @classmethod
def refresh_permissions(cls, group_permissions: list[GroupPermissionsDict]) -> None: def remove_old_permissions_from_added_permissions(
"""Adds new permission assignments and deletes old ones.""" cls,
initial_permission_assignments = PermissionAssignmentModel.query.all() added_permissions: AddedPermissionDict,
initial_user_to_group_assignments = UserGroupAssignmentModel.query.all() initial_permission_assignments: list[PermissionAssignmentModel],
group_permissions = group_permissions + cls.parse_permissions_yaml_into_group_info() initial_user_to_group_assignments: list[UserGroupAssignmentModel],
) -> None:
result = cls.add_permissions_from_group_permissions(group_permissions) added_permission_assignments = added_permissions["permission_assignments"]
desired_permission_assignments = result["permission_assignments"] added_group_identifiers = added_permissions["group_identifiers"]
desired_group_identifiers = result["group_identifiers"] added_user_to_group_identifiers = added_permissions["user_to_group_identifiers"]
desired_user_to_group_identifiers = result["user_to_group_identifiers"]
for ipa in initial_permission_assignments: for ipa in initial_permission_assignments:
if ipa not in desired_permission_assignments: if ipa not in added_permission_assignments:
db.session.delete(ipa) db.session.delete(ipa)
for iutga in initial_user_to_group_assignments: for iutga in initial_user_to_group_assignments:
@ -740,12 +723,23 @@ class AuthorizationService:
"username": iutga.user.username, "username": iutga.user.username,
"group_identifier": iutga.group.identifier, "group_identifier": iutga.group.identifier,
} }
if current_user_dict not in desired_user_to_group_identifiers: if current_user_dict not in added_user_to_group_identifiers:
db.session.delete(iutga) db.session.delete(iutga)
# do not remove the default user group # do not remove the default user group
desired_group_identifiers.add(current_app.config["SPIFFWORKFLOW_BACKEND_DEFAULT_USER_GROUP"]) added_group_identifiers.add(current_app.config["SPIFFWORKFLOW_BACKEND_DEFAULT_USER_GROUP"])
groups_to_delete = GroupModel.query.filter(GroupModel.identifier.not_in(desired_group_identifiers)).all() groups_to_delete = GroupModel.query.filter(GroupModel.identifier.not_in(added_group_identifiers)).all()
for gtd in groups_to_delete: for gtd in groups_to_delete:
db.session.delete(gtd) db.session.delete(gtd)
db.session.commit() db.session.commit()
@classmethod
def refresh_permissions(cls, group_permissions: list[GroupPermissionsDict]) -> None:
"""Adds new permission assignments and deletes old ones."""
initial_permission_assignments = PermissionAssignmentModel.query.all()
initial_user_to_group_assignments = UserGroupAssignmentModel.query.all()
group_permissions = group_permissions + cls.parse_permissions_yaml_into_group_info()
added_permissions = cls.add_permissions_from_group_permissions(group_permissions)
cls.remove_old_permissions_from_added_permissions(
added_permissions, initial_permission_assignments, initial_user_to_group_assignments
)