From fbb853dda99c75e726fc1aeb28299c4621add1a7 Mon Sep 17 00:00:00 2001 From: DerekFurstPitt Date: Thu, 30 Nov 2023 15:47:37 -0500 Subject: [PATCH 1/2] added fields ingest_task and assigned_to_group_name and their accompanying validators. Fixed bug in validate_if_retraction_permitted with group names --- src/schema/provenance_schema.yaml | 32 ++++++++++++++ src/schema/schema_validators.py | 69 ++++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 2 deletions(-) diff --git a/src/schema/provenance_schema.yaml b/src/schema/provenance_schema.yaml index 05174972..850383b4 100644 --- a/src/schema/provenance_schema.yaml +++ b/src/schema/provenance_schema.yaml @@ -490,6 +490,22 @@ ENTITIES: description: "A list of all status change events. Each entry in the list is a dictionary containing the change_timestamp, changed_by_email, previous_status, new_status" generated: true immutable: true + assigned_to_group_name: + type: string + description: The group who is responsible for the next step in the ingest process + before_property_create_validators: + - validate_in_admin_group + - validate_group_name + before_property_update_validators: + - validate_in_admin_group + - validate_group_name + ingest_task: + type: string + description: A description of the next task in the ingest process + before_property_create_validators: + - validate_in_admin_group + before_property_update_validators: + - validate_in_admin_group ############################################# Publication ############################################# Publication: @@ -1176,3 +1192,19 @@ ENTITIES: description: "A list of all status change events. Each entry in the list is a dictionary containing the change_timestamp, changed_by_email, previous_status, new_status" generated: true immutable: true + assigned_to_group_name: + type: string + description: The group who is responsible for the next step in the ingest process + before_property_create_validators: + - validate_in_admin_group + - validate_group_name + before_property_update_validators: + - validate_in_admin_group + - validate_group_name + ingest_task: + type: string + description: A description of the next task in the ingest process + before_property_create_validators: + - validate_in_admin_group + before_property_update_validators: + - validate_in_admin_group diff --git a/src/schema/schema_validators.py b/src/schema/schema_validators.py index 8c1269a5..ac495170 100644 --- a/src/schema/schema_validators.py +++ b/src/schema/schema_validators.py @@ -8,6 +8,7 @@ from schema import schema_errors from schema import schema_neo4j_queries from schema.schema_constants import SchemaConstants +from hubmap_commons import hm_auth logger = logging.getLogger(__name__) @@ -324,7 +325,7 @@ def validate_if_retraction_permitted(property_key, normalized_entity_type, reque # The property 'hmgroupids' is ALWAYS in the output with using schema_manager.get_user_info() # when the token in request is a nexus_token user_info = schema_manager.get_user_info(request) - hubmap_read_group_uuid = schema_manager.get_auth_helper_instance().groupNameToId('HuBMAP-READ')['uuid'] + hubmap_admin_group_uuid = schema_manager.get_auth_helper_instance().groupNameToId('HuBMAP-Data-Admin')['uuid'] except Exception as e: # Log the full stack trace, prepend a line with our message logger.exception(e) @@ -334,7 +335,7 @@ def validate_if_retraction_permitted(property_key, normalized_entity_type, reque # We treat such cases as the user not in the HuBMAP-READ group raise ValueError("Failed to parse the permission based on token, retraction is not allowed") - if hubmap_read_group_uuid not in user_info['hmgroupids']: + if hubmap_admin_group_uuid not in user_info['hmgroupids']: raise ValueError("Permission denied, retraction is not allowed") @@ -534,6 +535,70 @@ def validate_creation_action(property_key, normalized_entity_type, request, exis raise ValueError(f"The property {property_key} cannot be empty, when specified.") +""" +Validate that the user is in Hubmap-Data-Admin before creating or updating field 'assigned_to_group_name' + +Parameters +---------- +property_key : str + The target property key +normalized_type : str + Submission +request: Flask request object + The instance of Flask request passed in from application request +existing_data_dict : dict + A dictionary that contains all existing entity properties +new_data_dict : dict + The json data in request body, already after the regular validations +""" +def validate_in_admin_group(property_key, normalized_entity_type, request, existing_data_dict, new_data_dict): + try: + # The property 'hmgroupids' is ALWAYS in the output with using schema_manager.get_user_info() + # when the token in request is a nexus_token + user_info = schema_manager.get_user_info(request) + hubmap_admin_group_uuid = schema_manager.get_auth_helper_instance().groupNameToId('HuBMAP-Data-Admin')['uuid'] + except Exception as e: + # Log the full stack trace, prepend a line with our message + logger.exception(e) + + # If the token is not a groups token, no group information available + # The commons.hm_auth.AuthCache would return a Response with 500 error message + # We treat such cases as the user not in the HuBMAP-READ group + raise ValueError("Failed to parse the permission based on token, retraction is not allowed") + + if hubmap_admin_group_uuid not in user_info['hmgroupids']: + raise ValueError(f"Permission denied, not permitted to set property {property_key}") + + +""" +Validate that the provided group_name is one of the group name 'shortname' values where data_provider == true available +from hubmap-commons in the xxx-globus-groups.json file on entity creation + +Parameters +---------- +property_key : str + The target property key +normalized_type : str + Submission +request: Flask request object + The instance of Flask request passed in from application request +existing_data_dict : dict + A dictionary that contains all existing entity properties +new_data_dict : dict + The json data in request body, already after the regular validations +""" +def validate_group_name(property_key, normalized_entity_type, request, existing_data_dict, new_data_dict): + assigned_to_group_name = new_data_dict['assigned_to_group_name'] + globus_groups = schema_manager.get_auth_helper_instance().getHuBMAPGroupInfo() + shortnames = list({value.get("shortname") for value in globus_groups.values() if value.get("shortname") is not None}) + if assigned_to_group_name not in shortnames: + raise ValueError("Invalid value for 'assigned_to_group_name'") + is_data_provider = next((entry.get("data_provider", False) for entry in globus_groups.values() if entry.get("shortname") == assigned_to_group_name), False) + if not is_data_provider: + raise ValueError("Invalid group in 'assigned_to_group_name'. Must be a data provider") + + + #################################################################################################### ## Internal Functions #################################################################################################### From f83f39478d2d13007ccb1afa7b96a719e7b179e6 Mon Sep 17 00:00:00 2001 From: DerekFurstPitt Date: Fri, 1 Dec 2023 12:14:19 -0500 Subject: [PATCH 2/2] Optimized validate_group_name. No longer needs to iterate through the group twice. Also removed an old reference to read-group --- src/schema/schema_validators.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/schema/schema_validators.py b/src/schema/schema_validators.py index ac495170..ac3ad804 100644 --- a/src/schema/schema_validators.py +++ b/src/schema/schema_validators.py @@ -563,7 +563,7 @@ def validate_in_admin_group(property_key, normalized_entity_type, request, exist # If the token is not a groups token, no group information available # The commons.hm_auth.AuthCache would return a Response with 500 error message - # We treat such cases as the user not in the HuBMAP-READ group + # We treat such cases as the user not in the HuBMAP-Data group raise ValueError("Failed to parse the permission based on token, retraction is not allowed") if hubmap_admin_group_uuid not in user_info['hmgroupids']: @@ -590,10 +590,10 @@ def validate_in_admin_group(property_key, normalized_entity_type, request, exist def validate_group_name(property_key, normalized_entity_type, request, existing_data_dict, new_data_dict): assigned_to_group_name = new_data_dict['assigned_to_group_name'] globus_groups = schema_manager.get_auth_helper_instance().getHuBMAPGroupInfo() - shortnames = list({value.get("shortname") for value in globus_groups.values() if value.get("shortname") is not None}) - if assigned_to_group_name not in shortnames: + group_dict = next((entry for entry in globus_groups.values() if entry.get("shortname") == assigned_to_group_name), None) + if group_dict is None: raise ValueError("Invalid value for 'assigned_to_group_name'") - is_data_provider = next((entry.get("data_provider", False) for entry in globus_groups.values() if entry.get("shortname") == assigned_to_group_name), False) + is_data_provider = group_dict.get('data_provider') if not is_data_provider: raise ValueError("Invalid group in 'assigned_to_group_name'. Must be a data provider")