diff --git a/pymisp/api.py b/pymisp/api.py index 87a0366..0c94265 100644 --- a/pymisp/api.py +++ b/pymisp/api.py @@ -2638,7 +2638,7 @@ class PyMISP: for _r in self.roles(pythonify=True): if not isinstance(_r, MISPRole): continue - if _r.default_role: # type: ignore + if _r.default_role: role_id = get_uuid_or_id_from_abstract_misp(_r) break else: @@ -2696,6 +2696,40 @@ class PyMISP: to_return.append(nr) return to_return + def add_role(self, role: MISPRole, pythonify: bool = False) -> dict[str, Any] | MISPRole: + """Add a new role + + :param role: role to add + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ + r = self._prepare_request('POST', 'admin/roles/add', data=role) + role_j = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in role_j: + return role_j + new_misp_role = MISPRole() + new_misp_role.from_dict(**role_j) + return new_misp_role + + def update_role(self, role: MISPRole, role_id: int | None = None, pythonify: bool = False) -> dict[str, Any] | MISPRole: + """Update a role on a MISP instance + + :param role: role to update + :param role_id: id to update + :param pythonify: Returns a PyMISP Object instead of the plain json output + """ + if role_id is None: + uid = get_uuid_or_id_from_abstract_misp(role) + else: + uid = get_uuid_or_id_from_abstract_misp(role_id) + url = f'admin/roles/edit/{uid}' + r = self._prepare_request('POST', url, data=role) + updated_role = self._check_json_response(r) + if not (self.global_pythonify or pythonify) or 'errors' in updated_role: + return updated_role + updated_misp_role = MISPRole() + updated_misp_role.from_dict(**updated_role) + return updated_misp_role + def set_default_role(self, role: MISPRole | int | str | UUID) -> dict[str, Any] | list[dict[str, Any]]: """Set a default role for the new user accounts @@ -2706,6 +2740,15 @@ class PyMISP: response = self._prepare_request('POST', url) return self._check_json_response(response) + def delete_role(self, role: MISPRole | int | str | UUID) -> dict[str, Any] | list[dict[str, Any]]: + """Delete a role + + :param role: role to delete + """ + role_id = get_uuid_or_id_from_abstract_misp(role) + response = self._prepare_request('POST', f'admin/roles/delete/{role_id}') + return self._check_json_response(response) + # ## END Role ### # ## BEGIN Decaying Models ### diff --git a/pymisp/mispevent.py b/pymisp/mispevent.py index e19f351..74e5b4f 100644 --- a/pymisp/mispevent.py +++ b/pymisp/mispevent.py @@ -2260,14 +2260,48 @@ class MISPRole(AbstractMISP): def __init__(self, **kwargs: dict[str, Any]) -> None: super().__init__(**kwargs) - self.perm_admin: int - self.perm_site_admin: int + self.name: str + self.perm_add: bool + self.perm_modify: bool + self.perm_modify_org: bool + self.perm_publish: bool + self.perm_delegate: bool + self.perm_sync: bool + self.perm_admin: bool + self.perm_audit: bool + self.perm_auth: bool + self.perm_site_admin: bool + self.perm_regexp_access: bool + self.perm_tagger: bool + self.perm_template: bool + self.perm_sharing_group: bool + self.perm_tag_editor: bool + self.perm_sighting: bool + self.perm_object_template: bool + self.default_role: bool + self.memory_limit: str | int + self.max_execution_time: str | int + self.restricted_to_site_admin: bool + self.perm_publish_zmq: bool + self.perm_publish_kafka: bool + self.perm_decaying: bool + self.enforce_rate_limit: bool + self.rate_limit_count: str | int + self.perm_galaxy_editor: bool + self.perm_warninglist: bool + self.perm_view_feed_correlations: bool + self.perm_analyst_data: bool + self.permission: str + self.permission_description: str def from_dict(self, **kwargs) -> None: # type: ignore[no-untyped-def] if 'Role' in kwargs: kwargs = kwargs['Role'] super().from_dict(**kwargs) + def __repr__(self) -> str: + return '<{self.__class__.__name__}({self.name})'.format(self=self) + class MISPServer(AbstractMISP): diff --git a/tests/testlive_comprehensive.py b/tests/testlive_comprehensive.py index 3cd6538..0201207 100644 --- a/tests/testlive_comprehensive.py +++ b/tests/testlive_comprehensive.py @@ -26,7 +26,7 @@ try: MISPSharingGroup, MISPFeed, MISPServer, MISPUserSetting, MISPEventReport, MISPCorrelationExclusion, MISPGalaxyCluster, MISPGalaxy, MISPOrganisationBlocklist, MISPEventBlocklist, - MISPNote) + MISPNote, MISPRole) from pymisp.tools import CSVLoader, DomainIPObject, ASNObject, GenericObjectGenerator except ImportError: raise @@ -36,7 +36,7 @@ try: verifycert = False except ImportError as e: print(e) - url = 'https://10.197.206.83' + url = 'https://10.197.206.84' key = 'OdzzuBSnH83tEjvZbf7SFejC1kC3gS11Cnj2wxLk' verifycert = False @@ -79,6 +79,7 @@ class TestComprehensive(unittest.TestCase): cls.admin_misp_connector.set_server_setting('debug', 1, force=True) if not fast_mode: r = cls.admin_misp_connector.update_misp() + print(r) # Creates an org organisation = MISPOrganisation() organisation.name = 'Test Org' @@ -2168,6 +2169,19 @@ class TestComprehensive(unittest.TestCase): self.admin_misp_connector.set_default_role(3) roles = self.admin_misp_connector.roles(pythonify=True) self.assertTrue(isinstance(roles, list)) + try: + # Create a new role + new_role = MISPRole() + new_role.name = 'testrole' + new_role = self.admin_misp_connector.add_role(new_role, pythonify=True) + self.assertFalse(new_role.perm_sighting) + new_role.perm_sighting = True + new_role.max_execution_time = 1234 + updated_role = self.admin_misp_connector.update_role(new_role, pythonify=True) + self.assertTrue(updated_role.perm_sighting) + self.assertEqual(updated_role.max_execution_time, '1234') + finally: + self.admin_misp_connector.delete_role(new_role) def test_describe_types(self) -> None: remote = self.admin_misp_connector.describe_types_remote