From dbffcedc4942fe50f60dc573ceb18cf2d51fcbb6 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Fri, 2 May 2025 10:48:30 +0200 Subject: [PATCH] feat(exchange): add new check `exchange_mailbox_properties_auditing_e3_enabled` (#7642) Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com> --- prowler/CHANGELOG.md | 1 + .../m365/lib/powershell/m365_powershell.py | 66 +++++ .../__init__.py | 0 ...operties_auditing_e3_enabled.metadata.json | 30 +++ ..._mailbox_properties_auditing_e3_enabled.py | 74 ++++++ .../services/exchange/exchange_service.py | 97 +++++++ ...box_properties_auditing_e3_enabled_test.py | 240 ++++++++++++++++++ .../exchange/exchange_service_test.py | 115 +++++++++ 8 files changed, 623 insertions(+) create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/__init__.py create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.metadata.json create mode 100644 prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.py create mode 100644 tests/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled_test.py diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index 17cb4ada64..7fdbac2c9b 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -38,6 +38,7 @@ All notable changes to the **Prowler SDK** are documented in this file. - Add Prowler Threat Score Compliance Framework [(#7603)](https://github.com/prowler-cloud/prowler/pull/7603) - Add new check `sharepoint_onedrive_sync_restricted_unmanaged_devices` [(#7589)](https://github.com/prowler-cloud/prowler/pull/7589) - Add new check for Additional Storage restricted for Exchange in M365 [(#7638)](https://github.com/prowler-cloud/prowler/pull/7638) +- Add new check for Auditing Mailbox on E3 users is enabled for Exchange in M365 [(#7642)](https://github.com/prowler-cloud/prowler/pull/7642) - Add new check for SMTP Auth disabled for Exchange in M365 [(#7640)](https://github.com/prowler-cloud/prowler/pull/7640) - Add new check for MailTips full enabled for Exchange in M365 [(#7637)](https://github.com/prowler-cloud/prowler/pull/7637) diff --git a/prowler/providers/m365/lib/powershell/m365_powershell.py b/prowler/providers/m365/lib/powershell/m365_powershell.py index 1046a45b7d..9dc5d6ff1a 100644 --- a/prowler/providers/m365/lib/powershell/m365_powershell.py +++ b/prowler/providers/m365/lib/powershell/m365_powershell.py @@ -487,6 +487,72 @@ class M365PowerShell(PowerShellSession): "Get-HostedContentFilterPolicy | ConvertTo-Json", json_parse=True ) + def get_mailbox_audit_properties(self) -> dict: + """ + Get Mailbox Properties. + + Retrieves the properties of all mailboxes in the organization in Exchange Online. + + Args: + mailbox (str): The email address or identifier of the mailbox. + + Returns: + dict: Mailbox properties in JSON format. + + Example: + >>> get_mailbox_properties() + { + "UserPrincipalName": "User1", + "AuditEnabled": "false" + "AuditAdmin": [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send" + ], + "AuditDelegate": [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "ApplyRecord", + "MailItemsAccessed" + ], + "AuditOwner": [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send" + ], + "AuditLogAgeLimit": "90", + "Identity": "User1", + } + """ + return self.execute( + "Get-EXOMailbox -PropertySets Audit -ResultSize Unlimited | ConvertTo-Json", + json_parse=True, + ) + def get_transport_config(self) -> dict: """ Get Exchange Online Transport Configuration. diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/__init__.py b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.metadata.json b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.metadata.json new file mode 100644 index 0000000000..fccbe84533 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "m365", + "CheckID": "exchange_mailbox_properties_auditing_e3_enabled", + "CheckTitle": "Ensure mailbox auditing for E3 users is enabled.", + "CheckType": [], + "ServiceName": "exchange", + "SubServiceName": "", + "ResourceIdTemplate": "", + "Severity": "high", + "ResourceType": "Exchange Mailboxes Properties", + "Description": "Ensure mailbox auditing is enabled for all E3-licensed user mailboxes, including the configuration of audit actions for owners, delegates, and admins beyond the Microsoft defaults.", + "Risk": "If auditing is not properly enabled and configured, critical mailbox actions may go unrecorded, reducing the ability to investigate incidents, enforce compliance, or detect malicious behavior.", + "RelatedUrl": "https://learn.microsoft.com/en-us/purview/audit-mailboxes?view=o365-worldwide", + "Remediation": { + "Code": { + "CLI": "$AuditAdmin = @(\"ApplyRecord\", \"Copy\", \"Create\", \"FolderBind\", \"HardDelete\", \"Move\", \"MoveToDeletedItems\", \"SendAs\", \"SendOnBehalf\", \"SoftDelete\", \"Update\", \"UpdateCalendarDelegation\", \"UpdateFolderPermissions\", \"UpdateInboxRules\"); $AuditDelegate = @(\"ApplyRecord\", \"Create\", \"FolderBind\", \"HardDelete\", \"Move\", \"MoveToDeletedItems\", \"SendAs\", \"SendOnBehalf\", \"SoftDelete\", \"Update\", \"UpdateFolderPermissions\", \"UpdateInboxRules\"); $AuditOwner = @(\"ApplyRecord\", \"Create\", \"HardDelete\", \"MailboxLogin\", \"Move\", \"MoveToDeletedItems\", \"SoftDelete\", \"Update\", \"UpdateCalendarDelegation\", \"UpdateFolderPermissions\", \"UpdateInboxRules\"); $MBX = Get-EXOMailbox -ResultSize Unlimited | Where-Object { $_.RecipientTypeDetails -eq \"UserMailbox\" }; $MBX | Set-Mailbox -AuditEnabled $true -AuditLogAgeLimit 90 -AuditAdmin $AuditAdmin -AuditDelegate $AuditDelegate -AuditOwner $AuditOwner", + "NativeIaC": "", + "Other": "", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable mailbox auditing for all E3 user mailboxes and configure auditing for key mailbox actions for owners, delegates, and admins.", + "Url": "https://learn.microsoft.com/en-us/purview/audit-mailboxes?view=o365-worldwide" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.py b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.py new file mode 100644 index 0000000000..583d7a09b3 --- /dev/null +++ b/prowler/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled.py @@ -0,0 +1,74 @@ +from typing import List + +from prowler.lib.check.models import Check, CheckReportM365 +from prowler.providers.m365.services.exchange.exchange_client import exchange_client +from prowler.providers.m365.services.exchange.exchange_service import ( + AuditAdmin, + AuditDelegate, + AuditOwner, +) + + +class exchange_mailbox_properties_auditing_e3_enabled(Check): + """ + Check to ensure that mailbox auditing properties are enabled and properly configured. + + Attributes: + metadata: Metadata associated with the check (inherited from Check). + """ + + def execute(self) -> List[CheckReportM365]: + """ + Execute the check to validate that mailbox auditing properties are enabled and properly configured. + + This method retrieves all mailbox audit properties from the Exchange service and evaluates + whether auditing is enabled and correctly configured for each mailbox. A report is generated + for each mailbox. + + Returns: + List[CheckReportM365]: A list of findings with the status of each mailbox. + """ + findings = [] + + required_admin = {e.value for e in AuditAdmin} + required_delegate = {e.value for e in AuditDelegate} + required_owner = {e.value for e in AuditOwner} + + for mailbox in exchange_client.mailbox_audit_properties: + report = CheckReportM365( + metadata=self.metadata(), + resource=mailbox, + resource_name=mailbox.name, + resource_id=mailbox.identity, + ) + + report.status = "FAIL" + report.status_extended = ( + f"Mailbox Audit Properties for Mailbox {mailbox.name} is not enabled." + ) + + if mailbox.audit_enabled: + audit_admin = set(mailbox.audit_admin or []) + audit_delegate = set(mailbox.audit_delegate or []) + audit_owner = set(mailbox.audit_owner or []) + + if ( + required_admin.issubset(audit_admin) + and required_delegate.issubset(audit_delegate) + and required_owner.issubset(audit_owner) + ): + # The limit for E3 is 90 days, but we check >= 90 because E5 users can set it to more than 90 days + if mailbox.audit_log_age >= 90: + report.status = "PASS" + report.status_extended = f"Mailbox Audit Properties for Mailbox {mailbox.name} is enabled and properly configured." + else: + report.status_extended = f"Mailbox Audit Properties for Mailbox {mailbox.name} is enabled and properly configured but the audit log age is less than 90 days." + else: + report.status_extended = ( + f"Mailbox Audit Properties for Mailbox {mailbox.name} is enabled but not properly configured. " + f"Missing audit actions may exist." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index 03ad304c5e..8417e9c40e 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -1,3 +1,4 @@ +from enum import Enum from typing import Optional from pydantic import BaseModel @@ -16,6 +17,7 @@ class Exchange(M365Service): self.transport_rules = [] self.transport_config = None self.mailbox_policy = None + self.mailbox_audit_properties = [] if self.powershell: self.powershell.connect_exchange_online() @@ -25,6 +27,7 @@ class Exchange(M365Service): self.transport_rules = self._get_transport_rules() self.transport_config = self._get_transport_config() self.mailbox_policy = self._get_mailbox_policy() + self.mailbox_audit_properties = self._get_mailbox_audit_properties() self.powershell.close() def _get_organization_config(self): @@ -163,6 +166,44 @@ class Exchange(M365Service): ) return mailboxes_policy + def _get_mailbox_audit_properties(self): + logger.info("Microsoft365 - Getting mailbox audit properties...") + mailbox_audit_properties = [] + try: + mailbox_audit_properties_info = ( + self.powershell.get_mailbox_audit_properties() + ) + if not mailbox_audit_properties_info: + return mailbox_audit_properties + if isinstance(mailbox_audit_properties_info, dict): + mailbox_audit_properties_info = [mailbox_audit_properties_info] + for mailbox_audit_property in mailbox_audit_properties_info: + if mailbox_audit_property: + mailbox_audit_properties.append( + MailboxAuditProperties( + name=mailbox_audit_property.get("UserPrincipalName", ""), + audit_enabled=mailbox_audit_property.get( + "AuditEnabled", False + ), + audit_admin=mailbox_audit_property.get("AuditAdmin", []), + audit_delegate=mailbox_audit_property.get( + "AuditDelegate", [] + ), + audit_owner=mailbox_audit_property.get("AuditOwner", []), + audit_log_age=int( + mailbox_audit_property.get( + "AuditLogAgeLimit", "90.00:00:00" + ).split(".")[0] + ), + identity=mailbox_audit_property.get("Identity", ""), + ) + ) + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return mailbox_audit_properties + class Organization(BaseModel): name: str @@ -198,3 +239,59 @@ class TransportConfig(BaseModel): class MailboxPolicy(BaseModel): id: str additional_storage_enabled: bool + + +class MailboxAuditProperties(BaseModel): + name: str + audit_enabled: bool + audit_admin: list[str] + audit_delegate: list[str] + audit_owner: list[str] + audit_log_age: int + identity: str + + +class AuditAdmin(Enum): + APPLY_RECORD = "ApplyRecord" + COPY = "Copy" + CREATE = "Create" + FOLDER_BIND = "FolderBind" + HARD_DELETE = "HardDelete" + MOVE = "Move" + MOVE_TO_DELETED_ITEMS = "MoveToDeletedItems" + SEND_AS = "SendAs" + SEND_ON_BEHALF = "SendOnBehalf" + SOFT_DELETE = "SoftDelete" + UPDATE = "Update" + UPDATE_CALENDAR_DELEGATION = "UpdateCalendarDelegation" + UPDATE_FOLDER_PERMISSIONS = "UpdateFolderPermissions" + UPDATE_INBOX_RULES = "UpdateInboxRules" + + +class AuditDelegate(Enum): + APPLY_RECORD = "ApplyRecord" + CREATE = "Create" + FOLDER_BIND = "FolderBind" + HARD_DELETE = "HardDelete" + MOVE = "Move" + MOVE_TO_DELETED_ITEMS = "MoveToDeletedItems" + SEND_AS = "SendAs" + SEND_ON_BEHALF = "SendOnBehalf" + SOFT_DELETE = "SoftDelete" + UPDATE = "Update" + UPDATE_FOLDER_PERMISSIONS = "UpdateFolderPermissions" + UPDATE_INBOX_RULES = "UpdateInboxRules" + + +class AuditOwner(Enum): + APPLY_RECORD = "ApplyRecord" + CREATE = "Create" + HARD_DELETE = "HardDelete" + MAILBOX_LOGIN = "MailboxLogin" + MOVE = "Move" + MOVE_TO_DELETED_ITEMS = "MoveToDeletedItems" + SOFT_DELETE = "SoftDelete" + UPDATE = "Update" + UPDATE_CALENDAR_DELEGATION = "UpdateCalendarDelegation" + UPDATE_FOLDER_PERMISSIONS = "UpdateFolderPermissions" + UPDATE_INBOX_RULES = "UpdateInboxRules" diff --git a/tests/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled_test.py b/tests/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled_test.py new file mode 100644 index 0000000000..9985341194 --- /dev/null +++ b/tests/providers/m365/services/exchange/exchange_mailbox_properties_auditing_e3_enabled/exchange_mailbox_properties_auditing_e3_enabled_test.py @@ -0,0 +1,240 @@ +from unittest import mock + +from prowler.providers.m365.services.exchange.exchange_service import ( + AuditAdmin, + AuditDelegate, + AuditOwner, + MailboxAuditProperties, +) +from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider + + +class Test_exchange_mailbox_properties_auditing_e3_enabled: + def test_no_auditing_mailboxes(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 0 + + def test_auditing_fully_configured_and_log_age_valid(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [ + MailboxAuditProperties( + name="User1", + audit_enabled=True, + audit_admin=[e.value for e in AuditAdmin], + audit_delegate=[e.value for e in AuditDelegate], + audit_owner=[e.value for e in AuditOwner], + audit_log_age=180, + identity="User1", + ) + ] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Mailbox Audit Properties for Mailbox User1 is enabled and properly configured." + ) + assert result[0].resource_name == "User1" + assert result[0].resource_id == "User1" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.mailbox_audit_properties[0].dict() + ) + + def test_audit_enabled_but_incomplete_configuration(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [ + MailboxAuditProperties( + name="User2", + audit_enabled=True, + audit_admin=["SendAs"], + audit_delegate=["Send"], + audit_owner=["Update"], + audit_log_age=180, + identity="User2", + ) + ] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Mailbox Audit Properties for Mailbox User2 is enabled but not properly configured. Missing audit actions may exist." + ) + assert result[0].resource_name == "User2" + assert result[0].resource_id == "User2" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.mailbox_audit_properties[0].dict() + ) + + def test_audit_not_enabled(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [ + MailboxAuditProperties( + name="User3", + audit_enabled=False, + audit_admin=[], + audit_delegate=[], + audit_owner=[], + audit_log_age=0, + identity="User3", + ) + ] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Mailbox Audit Properties for Mailbox User3 is not enabled." + ) + assert result[0].resource_name == "User3" + assert result[0].resource_id == "User3" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.mailbox_audit_properties[0].dict() + ) + + def test_audit_enabled_but_log_age_too_low(self): + exchange_client = mock.MagicMock() + exchange_client.audited_tenant = "audited_tenant" + exchange_client.audited_domain = DOMAIN + + with ( + mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=set_mocked_m365_provider(), + ), + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + mock.patch( + "prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled.exchange_client", + new=exchange_client, + ), + ): + from prowler.providers.m365.services.exchange.exchange_mailbox_properties_auditing_e3_enabled.exchange_mailbox_properties_auditing_e3_enabled import ( + exchange_mailbox_properties_auditing_e3_enabled, + ) + + exchange_client.mailbox_audit_properties = [ + MailboxAuditProperties( + name="User4", + audit_enabled=True, + audit_admin=[e.value for e in AuditAdmin], + audit_delegate=[e.value for e in AuditDelegate], + audit_owner=[e.value for e in AuditOwner], + audit_log_age=30, + identity="User4", + ) + ] + + check = exchange_mailbox_properties_auditing_e3_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Mailbox Audit Properties for Mailbox User4 is enabled and properly configured but the audit log age is less than 90 days." + ) + assert result[0].resource_name == "User4" + assert result[0].resource_id == "User4" + assert result[0].location == "global" + assert ( + result[0].resource == exchange_client.mailbox_audit_properties[0].dict() + ) diff --git a/tests/providers/m365/services/exchange/exchange_service_test.py b/tests/providers/m365/services/exchange/exchange_service_test.py index 60e6e853eb..73cf90c6d9 100644 --- a/tests/providers/m365/services/exchange/exchange_service_test.py +++ b/tests/providers/m365/services/exchange/exchange_service_test.py @@ -6,6 +6,7 @@ from prowler.providers.m365.services.exchange.exchange_service import ( Exchange, ExternalMailConfig, MailboxAuditConfig, + MailboxAuditProperties, MailboxPolicy, Organization, TransportConfig, @@ -74,6 +75,57 @@ def mock_exchange_get_mailbox_policy(_): ) +def mock_exchange_get_mailbox_audit_properties(_): + return [ + MailboxAuditProperties( + name="User1", + audit_enabled=False, + audit_admin=[ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send", + ], + audit_delegate=[ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "ApplyRecord", + "MailItemsAccessed", + ], + audit_owner=[ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send", + ], + audit_log_age=90, + identity="test", + ) + ] + + class Test_Exchange_Service: def test_get_client(self): with ( @@ -230,3 +282,66 @@ class Test_Exchange_Service: assert transport_config.smtp_auth_disabled is True exchange_client.powershell.close() + + @patch( + "prowler.providers.m365.services.exchange.exchange_service.Exchange._get_mailbox_audit_properties", + new=mock_exchange_get_mailbox_audit_properties, + ) + def test_get_mailbox_audit_properties(self): + with ( + mock.patch( + "prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online" + ), + ): + exchange_client = Exchange( + set_mocked_m365_provider( + identity=M365IdentityInfo(tenant_domain=DOMAIN) + ) + ) + mailbox_audit_properties = exchange_client.mailbox_audit_properties + assert len(mailbox_audit_properties) == 1 + assert mailbox_audit_properties[0].name == "User1" + assert mailbox_audit_properties[0].audit_enabled is False + assert mailbox_audit_properties[0].audit_admin == [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send", + ] + assert mailbox_audit_properties[0].audit_delegate == [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "SendAs", + "SendOnBehalf", + "Create", + "UpdateFolderPermissions", + "UpdateInboxRules", + "ApplyRecord", + "MailItemsAccessed", + ] + assert mailbox_audit_properties[0].audit_owner == [ + "Update", + "MoveToDeletedItems", + "SoftDelete", + "HardDelete", + "UpdateFolderPermissions", + "UpdateInboxRules", + "UpdateCalendarDelegation", + "ApplyRecord", + "MailItemsAccessed", + "Send", + ] + assert mailbox_audit_properties[0].audit_log_age == 90 + assert mailbox_audit_properties[0].identity == "test" + exchange_client.powershell.close()