mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-17 17:41:50 +00:00
feat(exchange): add new check exchange_mailbox_properties_auditing_e3_enabled (#7642)
Co-authored-by: Andoni A. <14891798+andoniaf@users.noreply.github.com>
This commit is contained in:
committed by
Pepe Fagoaga
parent
5d4191a7fc
commit
dbffcedc49
@@ -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)
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
+30
@@ -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": ""
|
||||
}
|
||||
+74
@@ -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
|
||||
@@ -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"
|
||||
|
||||
+240
@@ -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()
|
||||
)
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user