diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index b6b807f3..8c341fb5 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -54,6 +54,10 @@ class SecurityAdmin: _valid_segment_traits = {} _extracted_key_value_pair_segment_traits_map = {} + _racf_key_map = {} + _racf_message_key_map = {} + _racf_key_map = {} + _racf_message_key_map = {} _case_sensitive_extracted_values = [] __running_userid = None _logger = Logger() @@ -119,6 +123,7 @@ def __init__( self._logger.log_experimental("Replace Existing Segment Traits") self.__replace_valid_segment_traits(replace_existing_segment_traits) if additional_secret_traits is not None: + self._logger.log_experimental("Add Additional Secret Traits") self.__add_additional_secret_traits(additional_secret_traits) self.set_running_userid(run_as_userid) @@ -169,7 +174,12 @@ def __raw_dump(self) -> None: if self.__debug: # Note, since the hex dump is logged to the console, # secrets will be redacted. - self._logger.log_hex_dump(raw_result_xml, self.__secret_traits) + self._logger.log_hex_dump( + raw_result_xml, + self.__secret_traits, + self._racf_key_map, + self._racf_message_key_map, + ) # ============================================================================ # Secrets Redaction @@ -244,6 +254,8 @@ def _make_request( self.__running_userid, ), self.__secret_traits, + self._racf_key_map, + self._racf_message_key_map, ) self.__clear_state(security_request) if isinstance(raw_result, list): diff --git a/pyracf/common/utilities/logger.py b/pyracf/common/utilities/logger.py index b6c48c51..13bd381b 100644 --- a/pyracf/common/utilities/logger.py +++ b/pyracf/common/utilities/logger.py @@ -11,16 +11,6 @@ class Logger: """Logging for pyRACF.""" - __racf_key_map = { - "audaltr": "audit", - "audcntl": "audit", - "audnone": "audit", - "audread": "audit", - "audupdt": "audit", - } - - __racf_message_key_map = {"uacc": "universal access"} - __ansi_reset = "\033[0m" __ansi_gray = "\033[2m" __ansi_green = "\033[32m" @@ -167,41 +157,36 @@ def __redact_string( This function employs the following regular expressions explained below - Regex 1 ("quoted") - This is designed to match the pattern TRAIT('value') by matching the TRAIT name: - {trait_key.upper()}, a variable (potentially zero) amount of spaces ( +){{0,}}, then the - ('value') portion which must start and end with (' and '), but can conceivably contain - any characters, but a negative lookbehind is used to look for any unescaped single quotes - .*?(? str: """ Redacts a list of specific secret traits in a result xml string. @@ -299,8 +286,9 @@ def redact_result_xml( return security_result for xml_key in secret_traits.values(): racf_key = xml_key.split(":")[1] if ":" in xml_key else xml_key - if racf_key in self.__racf_key_map: - racf_key = self.__racf_key_map[racf_key] + if racf_key in racf_key_map: + print(racf_key_map[racf_key]) + racf_key = racf_key_map[racf_key] if isinstance(security_result, bytes): match = re.search( rf"{racf_key.upper()}( +){{0,}}\(", security_result.decode("cp1047") @@ -310,8 +298,8 @@ def redact_result_xml( if not match: continue security_result = self.__redact_string(security_result, racf_key) - if racf_key in self.__racf_message_key_map: - racf_key = self.__racf_message_key_map[racf_key] + if racf_key in racf_message_key_map: + racf_key = racf_message_key_map[racf_key] if isinstance(security_result, bytes): security_result = re.sub( rf"([A-Z]*[0-9]*[A-Z]) [^<>]*{racf_key.upper()}[^<>]*<\/message>", @@ -457,7 +445,13 @@ def __indent_xml(self, minified_xml: str) -> str: indented_xml += f"{' ' * indent_level}{current_line}\n" return indented_xml[:-2] - def log_hex_dump(self, raw_result_xml: bytes, secret_traits: dict) -> None: + def log_hex_dump( + self, + raw_result_xml: bytes, + secret_traits: dict, + racf_key_map: dict, + racf_message_key_map: dict, + ) -> None: """ Log the raw result XML returned by IRRSMO00 as a hex dump. """ @@ -470,6 +464,8 @@ def log_hex_dump(self, raw_result_xml: bytes, secret_traits: dict) -> None: raw_result_xml = self.redact_result_xml( raw_result_xml, secret_traits, + racf_key_map, + racf_message_key_map, ) for byte in raw_result_xml: color_function = self.__green diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index 9233ee0c..e2348fea 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -63,6 +63,14 @@ def __init__( "dfp": {"dfp:owner": "racf:resowner", "dfp:ckds_data_key": "racf:datakey"}, "tme": {"tme:roles": "racf:roles"}, } + self._racf_key_map = { + "audaltr": "audit", + "audcntl": "audit", + "audnone": "audit", + "audread": "audit", + "audupdt": "audit", + } + self._racf_message_key_map = {"uacc": "universal access"} self._valid_segment_traits["base"].update( self._common_base_traits_data_set_generic ) diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 940c37f3..1a404616 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -238,6 +238,14 @@ def __init__( "sigrequired": "signatureRequired", }, } + self._racf_key_map = { + "audaltr": "audit", + "audcntl": "audit", + "audnone": "audit", + "audread": "audit", + "audupdt": "audit", + } + self._racf_message_key_map = {"uacc": "universal access"} super().__init__( "resource", irrsmo00_result_buffer_size=irrsmo00_result_buffer_size, diff --git a/tests/data_set/data_set_result_samples/alter_data_set_result_error_uacc_secret.json b/tests/common/common_result_samples/alter_data_set_result_error_uacc_secret.json similarity index 100% rename from tests/data_set/data_set_result_samples/alter_data_set_result_error_uacc_secret.json rename to tests/common/common_result_samples/alter_data_set_result_error_uacc_secret.json diff --git a/tests/data_set/data_set_result_samples/alter_data_set_result_success_owner_secret.json b/tests/common/common_result_samples/alter_data_set_result_success_owner_secret.json similarity index 100% rename from tests/data_set/data_set_result_samples/alter_data_set_result_success_owner_secret.json rename to tests/common/common_result_samples/alter_data_set_result_success_owner_secret.json diff --git a/tests/group/group_result_samples/alter_group_result_error_gid_secret.json b/tests/common/common_result_samples/alter_group_result_error_gid_secret.json similarity index 100% rename from tests/group/group_result_samples/alter_group_result_error_gid_secret.json rename to tests/common/common_result_samples/alter_group_result_error_gid_secret.json diff --git a/tests/group/group_result_samples/alter_group_result_success_gid_secret.json b/tests/common/common_result_samples/alter_group_result_success_gid_secret.json similarity index 100% rename from tests/group/group_result_samples/alter_group_result_success_gid_secret.json rename to tests/common/common_result_samples/alter_group_result_success_gid_secret.json diff --git a/tests/resource/resource_result_samples/alter_resource_overwrite_audit_result_success.xml b/tests/common/common_result_samples/alter_resource_overwrite_audit_result_success.xml similarity index 100% rename from tests/resource/resource_result_samples/alter_resource_overwrite_audit_result_success.xml rename to tests/common/common_result_samples/alter_resource_overwrite_audit_result_success.xml diff --git a/tests/resource/resource_result_samples/alter_resource_result_error_uacc_secret.json b/tests/common/common_result_samples/alter_resource_result_error_uacc_secret.json similarity index 100% rename from tests/resource/resource_result_samples/alter_resource_result_error_uacc_secret.json rename to tests/common/common_result_samples/alter_resource_result_error_uacc_secret.json diff --git a/tests/resource/resource_result_samples/alter_resource_result_success_audit_secret.json b/tests/common/common_result_samples/alter_resource_result_success_audit_secret.json similarity index 100% rename from tests/resource/resource_result_samples/alter_resource_result_success_audit_secret.json rename to tests/common/common_result_samples/alter_resource_result_success_audit_secret.json diff --git a/tests/resource/resource_result_samples/alter_resource_result_success_owner_secret.json b/tests/common/common_result_samples/alter_resource_result_success_owner_secret.json similarity index 100% rename from tests/resource/resource_result_samples/alter_resource_result_success_owner_secret.json rename to tests/common/common_result_samples/alter_resource_result_success_owner_secret.json diff --git a/tests/user/user_result_samples/alter_user_result_error_uid_secret.json b/tests/common/common_result_samples/alter_user_result_error_uid_secret.json similarity index 100% rename from tests/user/user_result_samples/alter_user_result_error_uid_secret.json rename to tests/common/common_result_samples/alter_user_result_error_uid_secret.json diff --git a/tests/user/user_result_samples/alter_user_result_success_inst_data.xml b/tests/common/common_result_samples/alter_user_result_success_inst_data.xml similarity index 100% rename from tests/user/user_result_samples/alter_user_result_success_inst_data.xml rename to tests/common/common_result_samples/alter_user_result_success_inst_data.xml diff --git a/tests/user/user_result_samples/alter_user_result_success_inst_data_secret.json b/tests/common/common_result_samples/alter_user_result_success_inst_data_secret.json similarity index 100% rename from tests/user/user_result_samples/alter_user_result_success_inst_data_secret.json rename to tests/common/common_result_samples/alter_user_result_success_inst_data_secret.json diff --git a/tests/user/user_result_samples/alter_user_result_extended_success.json b/tests/common/common_result_samples/alter_user_result_success_uid_secret.json similarity index 100% rename from tests/user/user_result_samples/alter_user_result_extended_success.json rename to tests/common/common_result_samples/alter_user_result_success_uid_secret.json diff --git a/tests/common/test_additional_secrets_redaction.py b/tests/common/test_additional_secrets_redaction.py index e2d38510..b5954908 100644 --- a/tests/common/test_additional_secrets_redaction.py +++ b/tests/common/test_additional_secrets_redaction.py @@ -5,6 +5,7 @@ import __init__ +import tests.common.test_common_constants as TestCommonConstants import tests.data_set.test_data_set_constants as TestDataSetConstants import tests.group.test_group_constants as TestGroupConstants import tests.resource.test_resource_constants as TestResourceConstants @@ -43,7 +44,7 @@ def test_user_admin_custom_secret_redacted_on_success( ) self.assertEqual( result, - TestUserConstants.TEST_ALTER_USER_RESULT_EXTENDED_SUCCESS_DICTIONARY, + TestCommonConstants.TEST_ALTER_USER_RESULT_SUCCESS_UID_SECRET_DICTIONARY, ) self.assertNotIn( TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_EXTENDED["omvs:uid"], @@ -67,7 +68,7 @@ def test_user_admin_custom_secret_redacted_on_error( ) self.assertEqual( exception.exception.result, - TestUserConstants.TEST_ALTER_USER_RESULT_ERROR_UID_SECRET_DICTIONARY, + TestCommonConstants.TEST_ALTER_USER_RESULT_ERROR_UID_SECRET_DICTIONARY, ) self.assertNotIn( TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_UID_ERROR["omvs:uid"], @@ -82,7 +83,7 @@ def test_user_admin_custom_secret_redacted_when_complex_characters( user_admin = UserAdmin(additional_secret_traits=["base:installation_data"]) call_racf_mock.side_effect = [ TestUserConstants.TEST_EXTRACT_USER_RESULT_BASE_ONLY_SUCCESS_XML, - TestUserConstants.TEST_ALTER_USER_RESULT_INST_DATA_SUCCESS_XML, + TestCommonConstants.TEST_ALTER_USER_RESULT_INST_DATA_SUCCESS_XML, ] result = user_admin.alter( "squidwrd", @@ -90,7 +91,7 @@ def test_user_admin_custom_secret_redacted_when_complex_characters( ) self.assertEqual( result, - TestUserConstants.TEST_ALTER_USER_RESULT_SUCCESS_INST_DATA_SECRET_DICTIONARY, + TestCommonConstants.TEST_ALTER_USER_RESULT_SUCCESS_INST_DATA_SECRET_DICTIONARY, ) self.assertNotIn( TestUserConstants.TEST_ALTER_USER_REQUEST_TRAITS_INST_DATA[ @@ -134,7 +135,7 @@ def test_group_admin_custom_secret_redacted_on_success( ) self.assertEqual( result, - TestGroupConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_GID_SECRET_DICTIONARY, + TestCommonConstants.TEST_ALTER_GROUP_RESULT_SUCCESS_GID_SECRET_DICTIONARY, ) self.assertNotIn( TestGroupConstants.TEST_ALTER_GROUP_REQUEST_TRAITS["omvs:gid"], @@ -158,7 +159,7 @@ def test_group_admin_custom_secret_redacted_on_error( ) self.assertEqual( exception.exception.result, - TestGroupConstants.TEST_ALTER_GROUP_RESULT_ERROR_GID_SECRET_DICTIONARY, + TestCommonConstants.TEST_ALTER_GROUP_RESULT_ERROR_GID_SECRET_DICTIONARY, ) self.assertNotIn( TestGroupConstants.TEST_ALTER_GROUP_REQUEST_ERROR_TRAITS["omvs:gid"], @@ -200,7 +201,7 @@ def test_resource_admin_custom_secret_redacted_on_success( ) self.assertEqual( result, - TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_OWNER_SECRET_DICTIONARY, + TestCommonConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_OWNER_SECRET_DICTIONARY, ) self.assertNotIn( TestResourceConstants.TEST_ALTER_RESOURCE_REQUEST_TRAITS["base:owner"], @@ -215,7 +216,7 @@ def test_resource_admin_custom_mapped_secret_redacted_on_success( resource_admin = ResourceAdmin(additional_secret_traits=["base:audit_update"]) call_racf_mock.side_effect = [ TestResourceConstants.TEST_EXTRACT_RESOURCE_RESULT_BASE_SUCCESS_XML, - TestResourceConstants.TEST_ALTER_RESOURCE_OVERWRITE_AUDIT_RESULT_SUCCESS_XML, + TestCommonConstants.TEST_ALTER_RESOURCE_OVERWRITE_AUDIT_RESULT_SUCCESS_XML, ] result = resource_admin.overwrite_audit_rules_by_access_level( "TESTING", @@ -224,7 +225,7 @@ def test_resource_admin_custom_mapped_secret_redacted_on_success( ) self.assertEqual( result, - TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_AUDIT_SECRET_DICTIONARY, + TestCommonConstants.TEST_ALTER_RESOURCE_RESULT_SUCCESS_AUDIT_SECRET_DICTIONARY, ) self.assertNotIn( "ALL", @@ -250,7 +251,7 @@ def test_resource_admin_custom_secret_redacted_on_error( ) self.assertEqual( exception.exception.result, - TestResourceConstants.TEST_ALTER_RESOURCE_RESULT_ERROR_UACC_SECRET_DICTIONARY, + TestCommonConstants.TEST_ALTER_RESOURCE_RESULT_ERROR_UACC_SECRET_DICTIONARY, ) self.assertNotIn( TestResourceConstants.TEST_ALTER_RESOURCE_REQUEST_ERROR_TRAITS[ @@ -295,7 +296,7 @@ def test_data_set_admin_custom_secret_redacted_on_success( ) self.assertEqual( result, - TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_OWNER_SECRET_DICTIONARY, + TestCommonConstants.TEST_ALTER_DATA_SET_RESULT_SUCCESS_OWNER_SECRET_DICTIONARY, ) self.assertNotIn( TestDataSetConstants.TEST_ALTER_DATA_SET_REQUEST_TRAITS["base:owner"], @@ -320,7 +321,7 @@ def test_data_set_admin_custom_secret_redacted_on_error( ) self.assertEqual( exception.exception.result, - TestDataSetConstants.TEST_ALTER_DATA_SET_RESULT_ERROR_UACC_SECRET_DICTIONARY, + TestCommonConstants.TEST_ALTER_DATA_SET_RESULT_ERROR_UACC_SECRET_DICTIONARY, ) self.assertNotIn( TestDataSetConstants.TEST_ALTER_DATA_SET_REQUEST_TRAITS[f"{secret_trait}"], diff --git a/tests/common/test_common_constants.py b/tests/common/test_common_constants.py index 7a0c83ff..869fdd39 100644 --- a/tests/common/test_common_constants.py +++ b/tests/common/test_common_constants.py @@ -97,6 +97,50 @@ def get_sample(sample_file: str) -> Union[str, bytes]: "extract_user_result_base_omvs_csdata_success.json" ) +# ============================================================================ +# Additional Secrets Redaction +# ============================================================================ + +TEST_ALTER_DATA_SET_RESULT_SUCCESS_OWNER_SECRET_DICTIONARY = get_sample( + "alter_data_set_result_success_owner_secret.json" +) +TEST_ALTER_DATA_SET_RESULT_ERROR_UACC_SECRET_DICTIONARY = get_sample( + "alter_data_set_result_error_uacc_secret.json" +) + +TEST_ALTER_GROUP_RESULT_SUCCESS_GID_SECRET_DICTIONARY = get_sample( + "alter_group_result_success_gid_secret.json" +) +TEST_ALTER_GROUP_RESULT_ERROR_GID_SECRET_DICTIONARY = get_sample( + "alter_group_result_error_gid_secret.json" +) + +TEST_ALTER_RESOURCE_OVERWRITE_AUDIT_RESULT_SUCCESS_XML = get_sample( + "alter_resource_overwrite_audit_result_success.xml" +) +TEST_ALTER_RESOURCE_RESULT_SUCCESS_OWNER_SECRET_DICTIONARY = get_sample( + "alter_resource_result_success_owner_secret.json" +) +TEST_ALTER_RESOURCE_RESULT_SUCCESS_AUDIT_SECRET_DICTIONARY = get_sample( + "alter_resource_result_success_audit_secret.json" +) +TEST_ALTER_RESOURCE_RESULT_ERROR_UACC_SECRET_DICTIONARY = get_sample( + "alter_resource_result_error_uacc_secret.json" +) + +TEST_ALTER_USER_RESULT_SUCCESS_UID_SECRET_DICTIONARY = get_sample( + "alter_user_result_success_uid_secret.json" +) +TEST_ALTER_USER_RESULT_ERROR_UID_SECRET_DICTIONARY = get_sample( + "alter_user_result_error_uid_secret.json" +) +TEST_ALTER_USER_RESULT_INST_DATA_SUCCESS_XML = get_sample( + "alter_user_result_success_inst_data.xml" +) +TEST_ALTER_USER_RESULT_SUCCESS_INST_DATA_SECRET_DICTIONARY = get_sample( + "alter_user_result_success_inst_data_secret.json" +) + # ============================================================================ # Run As UserId # ============================================================================ diff --git a/tests/data_set/test_data_set_constants.py b/tests/data_set/test_data_set_constants.py index 22af3969..cf050ab2 100644 --- a/tests/data_set/test_data_set_constants.py +++ b/tests/data_set/test_data_set_constants.py @@ -34,16 +34,10 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_ALTER_DATA_SET_RESULT_SUCCESS_DICTIONARY = get_sample( "alter_data_set_result_success.json" ) -TEST_ALTER_DATA_SET_RESULT_SUCCESS_OWNER_SECRET_DICTIONARY = get_sample( - "alter_data_set_result_success_owner_secret.json" -) TEST_ALTER_DATA_SET_RESULT_ERROR_XML = get_sample("alter_data_set_result_error.xml") TEST_ALTER_DATA_SET_RESULT_ERROR_DICTIONARY = get_sample( "alter_data_set_result_error.json" ) -TEST_ALTER_DATA_SET_RESULT_ERROR_UACC_SECRET_DICTIONARY = get_sample( - "alter_data_set_result_error_uacc_secret.json" -) # Extract Data Set TEST_EXTRACT_DATA_SET_RESULT_BASE_ONLY_SUCCESS_XML = get_sample( diff --git a/tests/group/test_group_constants.py b/tests/group/test_group_constants.py index 5af92c68..478a1ca9 100644 --- a/tests/group/test_group_constants.py +++ b/tests/group/test_group_constants.py @@ -26,14 +26,8 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_ALTER_GROUP_RESULT_SUCCESS_DICTIONARY = get_sample( "alter_group_result_success.json" ) -TEST_ALTER_GROUP_RESULT_SUCCESS_GID_SECRET_DICTIONARY = get_sample( - "alter_group_result_success_gid_secret.json" -) TEST_ALTER_GROUP_RESULT_ERROR_XML = get_sample("alter_group_result_error.xml") TEST_ALTER_GROUP_RESULT_ERROR_DICTIONARY = get_sample("alter_group_result_error.json") -TEST_ALTER_GROUP_RESULT_ERROR_GID_SECRET_DICTIONARY = get_sample( - "alter_group_result_error_gid_secret.json" -) # Extract Group TEST_EXTRACT_GROUP_RESULT_BASE_OMVS_SUCCESS_XML = get_sample( diff --git a/tests/resource/test_resource_constants.py b/tests/resource/test_resource_constants.py index 2e071c51..a1448ccd 100644 --- a/tests/resource/test_resource_constants.py +++ b/tests/resource/test_resource_constants.py @@ -25,25 +25,13 @@ def get_sample(sample_file: str) -> Union[str, bytes]: # Alter Resource TEST_ALTER_RESOURCE_RESULT_SUCCESS_XML = get_sample("alter_resource_result_success.xml") -TEST_ALTER_RESOURCE_OVERWRITE_AUDIT_RESULT_SUCCESS_XML = get_sample( - "alter_resource_overwrite_audit_result_success.xml" -) TEST_ALTER_RESOURCE_RESULT_SUCCESS_DICTIONARY = get_sample( "alter_resource_result_success.json" ) -TEST_ALTER_RESOURCE_RESULT_SUCCESS_OWNER_SECRET_DICTIONARY = get_sample( - "alter_resource_result_success_owner_secret.json" -) -TEST_ALTER_RESOURCE_RESULT_SUCCESS_AUDIT_SECRET_DICTIONARY = get_sample( - "alter_resource_result_success_audit_secret.json" -) TEST_ALTER_RESOURCE_RESULT_ERROR_XML = get_sample("alter_resource_result_error.xml") TEST_ALTER_RESOURCE_RESULT_ERROR_DICTIONARY = get_sample( "alter_resource_result_error.json" ) -TEST_ALTER_RESOURCE_RESULT_ERROR_UACC_SECRET_DICTIONARY = get_sample( - "alter_resource_result_error_uacc_secret.json" -) # Extract Resource TEST_EXTRACT_RESOURCE_RESULT_BASE_SUCCESS_XML = get_sample( diff --git a/tests/user/test_user_constants.py b/tests/user/test_user_constants.py index d3676ae9..aed1d865 100644 --- a/tests/user/test_user_constants.py +++ b/tests/user/test_user_constants.py @@ -65,18 +65,6 @@ def get_sample(sample_file: str) -> Union[str, bytes]: TEST_ALTER_USER_RESULT_EXTENDED_SUCCESS_XML = get_sample( "alter_user_result_extended_success.xml" ) -TEST_ALTER_USER_RESULT_EXTENDED_SUCCESS_DICTIONARY = get_sample( - "alter_user_result_extended_success.json" -) -TEST_ALTER_USER_RESULT_ERROR_UID_SECRET_DICTIONARY = get_sample( - "alter_user_result_error_uid_secret.json" -) -TEST_ALTER_USER_RESULT_INST_DATA_SUCCESS_XML = get_sample( - "alter_user_result_success_inst_data.xml" -) -TEST_ALTER_USER_RESULT_SUCCESS_INST_DATA_SECRET_DICTIONARY = get_sample( - "alter_user_result_success_inst_data_secret.json" -) # Extract User TEST_EXTRACT_USER_RESULT_BASE_OMVS_SUCCESS_XML = get_sample(