From 15f2c7a1b9406e62d96ed0735bb6ed4e72106530 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Thu, 2 Nov 2023 18:35:09 -0400 Subject: [PATCH 1/4] Clear State before raising errors Add state clearing before raising SegmentError or SegmentTraitError. Add unit test for this (Unit test for SegmentTraitError includes extract to simulate functionality of add when generateRequestOnly is not set) Signed-off-by: Elijah Swift --- pyracf/common/security_admin.py | 2 ++ tests/user/test_user_request_builder.py | 43 +++++++++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index 8ff40445..d9eec027 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -269,6 +269,7 @@ def _build_bool_segment_dictionaries(self, segments: List[str]) -> None: else: bad_segments.append(segment) if bad_segments: + self.__clear_state(SecurityRequest) raise SegmentError(bad_segments, self._profile_type) # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits @@ -287,6 +288,7 @@ def _build_segment_dictionaries(self, traits: dict) -> None: if not trait_valid: bad_traits.append(trait) if bad_traits: + self.__clear_state(SecurityRequest) raise SegmentTraitError(bad_traits, self._profile_type) # preserve segment traits for debug logging. diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index 282d773c..083c718e 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -140,6 +140,30 @@ def test_user_admin_build_add_request_with_bad_segment_traits(self): + f"combination for '{self.user_admin._profile_type}'.\n", ) + def test_user_admin_cleans_up_after_build_add_request_with_bad_segment_traits(self): + bad_trait = "omvs:bad_trait" + user_admin = UserAdmin( + generate_requests_only=True, + ) + with self.assertRaises(SegmentTraitError) as exception: + user_admin.add( + "squidwrd", TestUserConstants.TEST_ADD_USER_REQUEST_BAD_TRAITS + ) + self.assertEqual( + exception.exception.message, + "Unable to build Security Request.\n\n" + + f"'{bad_trait}' is not a known segment-trait " + + f"combination for '{self.user_admin._profile_type}'.\n", + ) + result = user_admin.extract("squidwrd", segments=["omvs"]) + self.assertEqual( + result, TestUserConstants.TEST_EXTRACT_USER_REQUEST_BASE_OMVS_XML + ) + result = self.user_admin.add( + "squidwrd", traits=TestUserConstants.TEST_ADD_USER_REQUEST_TRAITS + ) + self.assertEqual(result, TestUserConstants.TEST_ADD_USER_REQUEST_XML) + def test_user_admin_build_extract_request_with_bad_segment_name(self): bad_segment = "bad_segment" user_admin = UserAdmin( @@ -152,3 +176,22 @@ def test_user_admin_build_extract_request_with_bad_segment_name(self): "Unable to build Security Request.\n\n" + f"'{bad_segment}' is not a known segment for '{self.user_admin._profile_type}'.\n", ) + + def test_user_admin_cleans_up_after_build_extract_request_with_bad_segment_name( + self, + ): + bad_segment = "bad_segment" + user_admin = UserAdmin( + generate_requests_only=True, + ) + with self.assertRaises(SegmentError) as exception: + user_admin.extract("squidwrd", segments=["tso", bad_segment]) + self.assertEqual( + exception.exception.message, + "Unable to build Security Request.\n\n" + + f"'{bad_segment}' is not a known segment for '{self.user_admin._profile_type}'.\n", + ) + result = user_admin.extract("squidwrd", segments=["omvs"]) + self.assertEqual( + result, TestUserConstants.TEST_EXTRACT_USER_REQUEST_BASE_OMVS_XML + ) From d6e0d3ed82e8c781ead3c09a1a519805fba7e2af Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 3 Nov 2023 09:28:28 -0400 Subject: [PATCH 2/4] Function Rename Signed-off-by: Elijah Swift --- pyracf/access/access_admin.py | 4 ++-- pyracf/common/security_admin.py | 4 ++-- pyracf/connection/connection_admin.py | 2 +- pyracf/data_set/data_set_admin.py | 10 +++++----- pyracf/group/group_admin.py | 10 +++++----- pyracf/resource/resource_admin.py | 10 +++++----- pyracf/setropts/setropts_admin.py | 4 ++-- pyracf/user/user_admin.py | 10 +++++----- 8 files changed, 27 insertions(+), 27 deletions(-) diff --git a/pyracf/access/access_admin.py b/pyracf/access/access_admin.py index 40a129d7..46a13e4e 100644 --- a/pyracf/access/access_admin.py +++ b/pyracf/access/access_admin.py @@ -64,7 +64,7 @@ def permit( ) -> Union[dict, bytes]: """Create or change a permission""" traits["base:auth_id"] = auth_id - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) access_request = AccessRequest(resource, class_name, "set", volume, generic) self._add_traits_directly_to_request_xml_with_no_segments( access_request, alter=True @@ -81,7 +81,7 @@ def delete( ) -> Union[dict, bytes]: """Delete a permission.""" traits = {"base:auth_id": auth_id} - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) access_request = AccessRequest(resource, class_name, "del", volume, generic) self._add_traits_directly_to_request_xml_with_no_segments(access_request) return self._make_request(access_request) diff --git a/pyracf/common/security_admin.py b/pyracf/common/security_admin.py index d9eec027..00736756 100644 --- a/pyracf/common/security_admin.py +++ b/pyracf/common/security_admin.py @@ -260,7 +260,7 @@ def __validate_and_add_trait( self._trait_map[trait] = self._valid_segment_traits[segment][trait] return True - def _build_bool_segment_dictionaries(self, segments: List[str]) -> None: + def _build_segment_dictionary(self, segments: List[str]) -> None: """Build segment dictionaries for profile extract.""" bad_segments = [] for segment in segments: @@ -274,7 +274,7 @@ def _build_bool_segment_dictionaries(self, segments: List[str]) -> None: # preserve segment traits for debug logging. self.__preserved_segment_traits = self._segment_traits - def _build_segment_dictionaries(self, traits: dict) -> None: + def _build_segment_trait_dictionary(self, traits: dict) -> None: """Build segemnt dictionaries for each segment.""" bad_traits = [] for trait in traits: diff --git a/pyracf/connection/connection_admin.py b/pyracf/connection/connection_admin.py index 43049de5..2527118e 100644 --- a/pyracf/connection/connection_admin.py +++ b/pyracf/connection/connection_admin.py @@ -121,7 +121,7 @@ def take_away_group_access_attribute( # ============================================================================ def connect(self, userid: str, group: str, traits: dict = {}) -> Union[dict, bytes]: """Create or change a group connection.""" - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) connection_request = ConnectionRequest(userid, group, "set") self._add_traits_directly_to_request_xml_with_no_segments( connection_request, alter=True diff --git a/pyracf/data_set/data_set_admin.py b/pyracf/data_set/data_set_admin.py index 41edc281..1995e5af 100644 --- a/pyracf/data_set/data_set_admin.py +++ b/pyracf/data_set/data_set_admin.py @@ -105,7 +105,7 @@ def add( ) -> Union[dict, bytes]: """Create a new data set profile.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request) return self._make_request(data_set_request) @@ -118,7 +118,7 @@ def add( except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH35003I"): raise exception - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request) return self._make_request(data_set_request) @@ -132,7 +132,7 @@ def alter( ) -> Union[dict, bytes]: """Alter an existing data set profile.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request, alter=True) return self._make_request(data_set_request, irrsmo00_precheck=True) @@ -144,7 +144,7 @@ def alter( raise AlterOperationError(data_set, self._profile_type) if not self._get_field(profile, "base", "name") == data_set.lower(): raise AlterOperationError(data_set, self._profile_type) - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) data_set_request = DataSetRequest(data_set, "set", volume, generic) self._build_xml_segments(data_set_request, alter=True) return self._make_request(data_set_request, irrsmo00_precheck=True) @@ -158,7 +158,7 @@ def extract( profile_only: bool = False, ) -> Union[dict, bytes]: """Extract a data set profile.""" - self._build_bool_segment_dictionaries(segments) + self._build_segment_dictionary(segments) data_set_request = DataSetRequest(data_set, "listdata", volume, generic) self._build_xml_segments(data_set_request, extract=True) result = self._extract_and_check_result(data_set_request) diff --git a/pyracf/group/group_admin.py b/pyracf/group/group_admin.py index daaf0ec6..63b22f7b 100644 --- a/pyracf/group/group_admin.py +++ b/pyracf/group/group_admin.py @@ -123,7 +123,7 @@ def set_ovm_gid(self, group: str, gid: int) -> Union[dict, bytes]: def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: """Create a new group.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request) return self._make_request(group_request) @@ -132,7 +132,7 @@ def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH51003I"): raise exception - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request) return self._make_request(group_request) @@ -141,7 +141,7 @@ def add(self, group: str, traits: dict = {}) -> Union[dict, bytes]: def alter(self, group: str, traits: dict) -> Union[dict, bytes]: """Alter an existing group.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request, alter=True) return self._make_request(group_request, irrsmo00_precheck=True) @@ -149,7 +149,7 @@ def alter(self, group: str, traits: dict) -> Union[dict, bytes]: self.extract(group) except SecurityRequestError: raise AlterOperationError(group, self._profile_type) - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) group_request = GroupRequest(group, "set") self._build_xml_segments(group_request, alter=True) return self._make_request(group_request, irrsmo00_precheck=True) @@ -158,7 +158,7 @@ def extract( self, group: str, segments: List[str] = [], profile_only: bool = False ) -> Union[dict, bytes]: """Extract a group's profile.""" - self._build_bool_segment_dictionaries(segments) + self._build_segment_dictionary(segments) group_request = GroupRequest(group, "listdata") self._build_xml_segments(group_request, extract=True) result = self._extract_and_check_result(group_request) diff --git a/pyracf/resource/resource_admin.py b/pyracf/resource/resource_admin.py index 9e0d5d4e..f42108d1 100644 --- a/pyracf/resource/resource_admin.py +++ b/pyracf/resource/resource_admin.py @@ -487,7 +487,7 @@ def add( ) -> Union[dict, bytes]: """Create a new general resource profile.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request) return self._make_request(profile_request) @@ -498,7 +498,7 @@ def add( except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH13003I"): raise exception - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request) return self._make_request(profile_request) @@ -506,7 +506,7 @@ def add( def alter(self, resource: str, class_name: str, traits: dict) -> Union[dict, bytes]: """Alter an existing general resource profile.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request, alter=True) return self._make_request(profile_request, irrsmo00_precheck=True) @@ -516,7 +516,7 @@ def alter(self, resource: str, class_name: str, traits: dict) -> Union[dict, byt raise AlterOperationError(resource, class_name) if not self._get_field(profile, "base", "name") == resource.lower(): raise AlterOperationError(resource, class_name) - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) profile_request = ResourceRequest(resource, class_name, "set") self._build_xml_segments(profile_request, alter=True) return self._make_request(profile_request, irrsmo00_precheck=True) @@ -529,7 +529,7 @@ def extract( profile_only: bool = False, ) -> Union[dict, bytes]: """Extract a general resource profile.""" - self._build_bool_segment_dictionaries(segments) + self._build_segment_dictionary(segments) resource_request = ResourceRequest(resource, class_name, "listdata") self._build_xml_segments(resource_request, extract=True) result = self._extract_and_check_result(resource_request) diff --git a/pyracf/setropts/setropts_admin.py b/pyracf/setropts/setropts_admin.py index 12fcd952..0b3230ab 100644 --- a/pyracf/setropts/setropts_admin.py +++ b/pyracf/setropts/setropts_admin.py @@ -313,7 +313,7 @@ def remove_raclist_classes( # ============================================================================ def list_racf_options(self, options_only: bool = False) -> Union[dict, bytes]: """List RACF options.""" - self._build_segment_dictionaries({"base:list": True}) + self._build_segment_trait_dictionary({"base:list": True}) setropts_request = SetroptsRequest() self._add_traits_directly_to_request_xml_with_no_segments(setropts_request) result = self._extract_and_check_result(setropts_request) @@ -323,7 +323,7 @@ def list_racf_options(self, options_only: bool = False) -> Union[dict, bytes]: def alter(self, options: dict = {}) -> Union[dict, bytes]: """Update RACF options.""" - self._build_segment_dictionaries(options) + self._build_segment_trait_dictionary(options) setropts_request = SetroptsRequest() self._add_traits_directly_to_request_xml_with_no_segments( setropts_request, alter=True diff --git a/pyracf/user/user_admin.py b/pyracf/user/user_admin.py index a126c58e..beba75cd 100644 --- a/pyracf/user/user_admin.py +++ b/pyracf/user/user_admin.py @@ -769,7 +769,7 @@ def set_tso_data_set_allocation_unit( def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: """Create a new user.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request) return self._make_request(user_request) @@ -778,7 +778,7 @@ def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: except SecurityRequestError as exception: if not exception.contains_error_message(self._profile_type, "ICH30001I"): raise exception - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request) return self._make_request(user_request) @@ -787,7 +787,7 @@ def add(self, userid: str, traits: dict = {}) -> Union[dict, bytes]: def alter(self, userid: str, traits: dict) -> Union[dict, bytes]: """Alter an existing user.""" if self._generate_requests_only: - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request, alter=True) return self._make_request(user_request, irrsmo00_precheck=True) @@ -795,7 +795,7 @@ def alter(self, userid: str, traits: dict) -> Union[dict, bytes]: self.extract(userid) except SecurityRequestError: raise AlterOperationError(userid, self._profile_type) - self._build_segment_dictionaries(traits) + self._build_segment_trait_dictionary(traits) user_request = UserRequest(userid, "set") self._build_xml_segments(user_request, alter=True) return self._make_request(user_request, irrsmo00_precheck=True) @@ -804,7 +804,7 @@ def extract( self, userid: str, segments: List[str] = [], profile_only: bool = False ) -> Union[dict, bytes]: """Extract a user's profile.""" - self._build_bool_segment_dictionaries(segments) + self._build_segment_dictionary(segments) user_request = UserRequest(userid, "listdata") self._build_xml_segments(user_request, extract=True) result = self._extract_and_check_result(user_request) From 648fd0a236c4a0aad2a9c31335eb06b0d838c567 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 3 Nov 2023 09:52:02 -0400 Subject: [PATCH 3/4] Update test_user_request_builder.py added comment to describe need for extract call in new test. Signed-off-by: Elijah Swift --- tests/user/test_user_request_builder.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index 083c718e..da5b81bf 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -140,6 +140,9 @@ def test_user_admin_build_add_request_with_bad_segment_traits(self): + f"combination for '{self.user_admin._profile_type}'.\n", ) +# Since this test uses GenerateRequestsOnly, the "Add" after the AddOperationError is returned +# does not begin with an "Extract" call. This is necessary to recreate the error, so an extra +# extract call was added to simulate this behavior. def test_user_admin_cleans_up_after_build_add_request_with_bad_segment_traits(self): bad_trait = "omvs:bad_trait" user_admin = UserAdmin( From eca4e7cb020a59f2965d73b47e9eec56c8a586f5 Mon Sep 17 00:00:00 2001 From: Elijah Swift Date: Fri, 3 Nov 2023 10:08:21 -0400 Subject: [PATCH 4/4] Update test_user_request_builder.py Signed-off-by: Elijah Swift --- tests/user/test_user_request_builder.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/user/test_user_request_builder.py b/tests/user/test_user_request_builder.py index da5b81bf..7c7a15f5 100644 --- a/tests/user/test_user_request_builder.py +++ b/tests/user/test_user_request_builder.py @@ -140,9 +140,9 @@ def test_user_admin_build_add_request_with_bad_segment_traits(self): + f"combination for '{self.user_admin._profile_type}'.\n", ) -# Since this test uses GenerateRequestsOnly, the "Add" after the AddOperationError is returned -# does not begin with an "Extract" call. This is necessary to recreate the error, so an extra -# extract call was added to simulate this behavior. + # Since this test uses generate_requests_only, the "Add" after the AddOperationError is + # returned does not begin with an "Extract" call. This is necessary to recreate the error, + # so an extra extract call was added to simulate this behavior. def test_user_admin_cleans_up_after_build_add_request_with_bad_segment_traits(self): bad_trait = "omvs:bad_trait" user_admin = UserAdmin(