From c1fba262cae438dc8724db369339d325b9d4293e Mon Sep 17 00:00:00 2001 From: MarioRgzLpz Date: Fri, 27 Dec 2024 11:08:02 +0100 Subject: [PATCH 1/3] feat(entra): Add new service Entra for Microsoft365 --- .../services/entramicrosoft/__init__.py | 0 .../entramicrosoft/entramicrosoft_client.py | 6 ++ .../entramicrosoft/entramicrosoft_service.py | 58 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 100644 prowler/providers/microsoft365/services/entramicrosoft/__init__.py create mode 100644 prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_client.py create mode 100644 prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_service.py diff --git a/prowler/providers/microsoft365/services/entramicrosoft/__init__.py b/prowler/providers/microsoft365/services/entramicrosoft/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_client.py b/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_client.py new file mode 100644 index 00000000000..9a430332a68 --- /dev/null +++ b/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_client.py @@ -0,0 +1,6 @@ +from prowler.providers.common.provider import Provider +from prowler.providers.microsoft365.services.entramicrosoft.entramicrosoft_service import ( + Entra, +) + +entra_client = Entra(Provider.get_global_provider()) diff --git a/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_service.py b/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_service.py new file mode 100644 index 00000000000..b4992f858cd --- /dev/null +++ b/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_service.py @@ -0,0 +1,58 @@ +from asyncio import gather, get_event_loop +from typing import Optional + +from msgraph.generated.models.default_user_role_permissions import ( + DefaultUserRolePermissions, +) +from pydantic import BaseModel + +from prowler.lib.logger import logger +from prowler.providers.microsoft365.lib.service.service import Microsoft365Service +from prowler.providers.microsoft365.microsoft365_provider import Microsoft365Provider + + +class Entra(Microsoft365Service): + def __init__(self, provider: Microsoft365Provider): + super().__init__(provider) + + loop = get_event_loop() + + attributes = loop.run_until_complete( + gather( + self._get_authorization_policy(), + ) + ) + + self.authorization_policy = attributes[0] + + async def _get_authorization_policy(self): + logger.info("Entra - Getting authorization policy...") + + authorization_policy = {} + try: + auth_policy = await self.client.policies.authorization_policy.get() + authorization_policy.update( + { + AuthorizationPolicy( + id=auth_policy.id, + name=auth_policy.display_name, + description=auth_policy.description, + default_user_role_permissions=getattr( + auth_policy, "default_user_role_permissions", None + ), + ) + } + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + + return authorization_policy + + +class AuthorizationPolicy(BaseModel): + id: str + name: str + description: str + default_user_role_permissions: Optional[DefaultUserRolePermissions] From a4045e24fed365a2c39255fe110c5bb0ec7bba66 Mon Sep 17 00:00:00 2001 From: MarioRgzLpz Date: Fri, 27 Dec 2024 11:09:25 +0100 Subject: [PATCH 2/3] feat(entra): Add test for entra service --- .../entramicrosoft_service_test.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/providers/microsoft365/services/entramicrosoft/entramicrosoft_service_test.py diff --git a/tests/providers/microsoft365/services/entramicrosoft/entramicrosoft_service_test.py b/tests/providers/microsoft365/services/entramicrosoft/entramicrosoft_service_test.py new file mode 100644 index 00000000000..3433f2b0661 --- /dev/null +++ b/tests/providers/microsoft365/services/entramicrosoft/entramicrosoft_service_test.py @@ -0,0 +1,43 @@ +from unittest.mock import patch + +from prowler.providers.microsoft365.models import Microsoft365IdentityInfo +from prowler.providers.microsoft365.services.entramicrosoft.entramicrosoft_service import ( + AuthorizationPolicy, + Entra, +) +from tests.providers.microsoft365.microsoft365_fixtures import ( + DOMAIN, + set_mocked_microsoft365_provider, +) + + +async def mock_entra_get_authorization_policy(_): + return { + AuthorizationPolicy( + id="id-1", + name="Name 1", + description="Description 1", + default_user_role_permissions=None, + ) + } + + +@patch( + "prowler.providers.microsoft365.services.entramicrosoft.entramicrosoft_service.Entra._get_authorization_policy", + new=mock_entra_get_authorization_policy, +) +class Test_Entra_Service: + def test_get_client(self): + admincenter_client = Entra( + set_mocked_microsoft365_provider( + identity=Microsoft365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + assert admincenter_client.client.__class__.__name__ == "GraphServiceClient" + + def test_get_authorization_policy(self): + entra_client = Entra(set_mocked_microsoft365_provider()) + assert entra_client.authorization_policy.id == "id-1" + assert entra_client.authorization_policy.name == "Name 1" + assert entra_client.authorization_policy.description == "Description 1" + assert not entra_client.authorization_policy.default_user_role_permissions From ee80d92be7e6a129876ad8a318beda9ea0c4dae2 Mon Sep 17 00:00:00 2001 From: MarioRgzLpz Date: Fri, 3 Jan 2025 11:45:41 +0100 Subject: [PATCH 3/3] fix(entra): Rename service to entra and fix service tests --- .../{entramicrosoft => entra}/__init__.py | 0 .../entra_client.py} | 4 +--- .../entra_service.py} | 5 ++++- .../entra_service_test.py} | 16 +++++++++------- 4 files changed, 14 insertions(+), 11 deletions(-) rename prowler/providers/microsoft365/services/{entramicrosoft => entra}/__init__.py (100%) rename prowler/providers/microsoft365/services/{entramicrosoft/entramicrosoft_client.py => entra/entra_client.py} (50%) rename prowler/providers/microsoft365/services/{entramicrosoft/entramicrosoft_service.py => entra/entra_service.py} (94%) rename tests/providers/microsoft365/services/{entramicrosoft/entramicrosoft_service_test.py => entra/entra_service_test.py} (63%) diff --git a/prowler/providers/microsoft365/services/entramicrosoft/__init__.py b/prowler/providers/microsoft365/services/entra/__init__.py similarity index 100% rename from prowler/providers/microsoft365/services/entramicrosoft/__init__.py rename to prowler/providers/microsoft365/services/entra/__init__.py diff --git a/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_client.py b/prowler/providers/microsoft365/services/entra/entra_client.py similarity index 50% rename from prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_client.py rename to prowler/providers/microsoft365/services/entra/entra_client.py index 9a430332a68..1a3b921adf3 100644 --- a/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_client.py +++ b/prowler/providers/microsoft365/services/entra/entra_client.py @@ -1,6 +1,4 @@ from prowler.providers.common.provider import Provider -from prowler.providers.microsoft365.services.entramicrosoft.entramicrosoft_service import ( - Entra, -) +from prowler.providers.microsoft365.services.entra.entra_service import Entra entra_client = Entra(Provider.get_global_provider()) diff --git a/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_service.py b/prowler/providers/microsoft365/services/entra/entra_service.py similarity index 94% rename from prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_service.py rename to prowler/providers/microsoft365/services/entra/entra_service.py index b4992f858cd..2ecf740aa70 100644 --- a/prowler/providers/microsoft365/services/entramicrosoft/entramicrosoft_service.py +++ b/prowler/providers/microsoft365/services/entra/entra_service.py @@ -33,7 +33,7 @@ async def _get_authorization_policy(self): auth_policy = await self.client.policies.authorization_policy.get() authorization_policy.update( { - AuthorizationPolicy( + auth_policy.id: AuthorizationPolicy( id=auth_policy.id, name=auth_policy.display_name, description=auth_policy.description, @@ -56,3 +56,6 @@ class AuthorizationPolicy(BaseModel): name: str description: str default_user_role_permissions: Optional[DefaultUserRolePermissions] + + class Config: + arbitrary_types_allowed = True diff --git a/tests/providers/microsoft365/services/entramicrosoft/entramicrosoft_service_test.py b/tests/providers/microsoft365/services/entra/entra_service_test.py similarity index 63% rename from tests/providers/microsoft365/services/entramicrosoft/entramicrosoft_service_test.py rename to tests/providers/microsoft365/services/entra/entra_service_test.py index 3433f2b0661..86109478e2a 100644 --- a/tests/providers/microsoft365/services/entramicrosoft/entramicrosoft_service_test.py +++ b/tests/providers/microsoft365/services/entra/entra_service_test.py @@ -1,7 +1,7 @@ from unittest.mock import patch from prowler.providers.microsoft365.models import Microsoft365IdentityInfo -from prowler.providers.microsoft365.services.entramicrosoft.entramicrosoft_service import ( +from prowler.providers.microsoft365.services.entra.entra_service import ( AuthorizationPolicy, Entra, ) @@ -13,7 +13,7 @@ async def mock_entra_get_authorization_policy(_): return { - AuthorizationPolicy( + "id-1": AuthorizationPolicy( id="id-1", name="Name 1", description="Description 1", @@ -23,7 +23,7 @@ async def mock_entra_get_authorization_policy(_): @patch( - "prowler.providers.microsoft365.services.entramicrosoft.entramicrosoft_service.Entra._get_authorization_policy", + "prowler.providers.microsoft365.services.entra.entra_service.Entra._get_authorization_policy", new=mock_entra_get_authorization_policy, ) class Test_Entra_Service: @@ -37,7 +37,9 @@ def test_get_client(self): def test_get_authorization_policy(self): entra_client = Entra(set_mocked_microsoft365_provider()) - assert entra_client.authorization_policy.id == "id-1" - assert entra_client.authorization_policy.name == "Name 1" - assert entra_client.authorization_policy.description == "Description 1" - assert not entra_client.authorization_policy.default_user_role_permissions + assert entra_client.authorization_policy["id-1"].id == "id-1" + assert entra_client.authorization_policy["id-1"].name == "Name 1" + assert entra_client.authorization_policy["id-1"].description == "Description 1" + assert not entra_client.authorization_policy[ + "id-1" + ].default_user_role_permissions