mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
fix(m365): Support multiple Exchange mailbox policies (#9241)
Co-authored-by: HugoPBrito <hugopbrit@gmail.com>
This commit is contained in:
@@ -14,6 +14,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
|
||||
|
||||
### Fixed
|
||||
- `sharepoint_external_sharing_managed` check to handle external sharing disabled at organization level [(#9298)](https://github.com/prowler-cloud/prowler/pull/9298)
|
||||
- Support multiple Exchange mailbox policies in M365 `exchange_mailbox_policy_additional_storage_restricted` check [(#9241)](https://github.com/prowler-cloud/prowler/pull/9241)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -13,32 +13,28 @@ class exchange_mailbox_policy_additional_storage_restricted(Check):
|
||||
def execute(self) -> List[CheckReportM365]:
|
||||
"""Run the check to validate Exchange mailbox policy restrictions.
|
||||
|
||||
Iterates through the mailbox policy configuration to determine if additional storage
|
||||
providers are restricted and generates a report based on the policy status.
|
||||
Iterates through all mailbox policies to determine if additional storage
|
||||
providers are restricted and generates reports for each policy.
|
||||
|
||||
Returns:
|
||||
List[CheckReportM365]: A list of reports with the restriction status for the mailbox policy.
|
||||
List[CheckReportM365]: A list of reports with the restriction status for each mailbox policy.
|
||||
"""
|
||||
findings = []
|
||||
mailbox_policy = exchange_client.mailbox_policy
|
||||
if mailbox_policy:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=mailbox_policy,
|
||||
resource_name="Exchange Mailbox Policy",
|
||||
resource_id=mailbox_policy.id,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
"Exchange mailbox policy allows additional storage providers."
|
||||
)
|
||||
|
||||
if not mailbox_policy.additional_storage_enabled:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
"Exchange mailbox policy restricts additional storage providers."
|
||||
for mailbox_policy in exchange_client.mailbox_policies:
|
||||
if mailbox_policy:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=mailbox_policy,
|
||||
resource_name=f"Exchange Mailbox Policy - {mailbox_policy.id}",
|
||||
resource_id=mailbox_policy.id,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Exchange mailbox policy '{mailbox_policy.id}' allows additional storage providers."
|
||||
|
||||
findings.append(report)
|
||||
if not mailbox_policy.additional_storage_enabled:
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Exchange mailbox policy '{mailbox_policy.id}' restricts additional storage providers."
|
||||
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
@@ -16,7 +16,7 @@ class Exchange(M365Service):
|
||||
self.external_mail_config = []
|
||||
self.transport_rules = []
|
||||
self.transport_config = None
|
||||
self.mailbox_policy = None
|
||||
self.mailbox_policies = []
|
||||
self.role_assignment_policies = []
|
||||
self.mailbox_audit_properties = []
|
||||
|
||||
@@ -27,7 +27,7 @@ class Exchange(M365Service):
|
||||
self.external_mail_config = self._get_external_mail_config()
|
||||
self.transport_rules = self._get_transport_rules()
|
||||
self.transport_config = self._get_transport_config()
|
||||
self.mailbox_policy = self._get_mailbox_policy()
|
||||
self.mailbox_policies = self._get_mailbox_policy()
|
||||
self.role_assignment_policies = self._get_role_assignment_policies()
|
||||
self.mailbox_audit_properties = self._get_mailbox_audit_properties()
|
||||
self.powershell.close()
|
||||
@@ -164,21 +164,27 @@ class Exchange(M365Service):
|
||||
|
||||
def _get_mailbox_policy(self):
|
||||
logger.info("Microsoft365 - Getting mailbox policy configuration...")
|
||||
mailboxes_policy = None
|
||||
mailbox_policies = []
|
||||
try:
|
||||
mailbox_policy = self.powershell.get_mailbox_policy()
|
||||
if mailbox_policy:
|
||||
mailboxes_policy = MailboxPolicy(
|
||||
id=mailbox_policy.get("Id", ""),
|
||||
additional_storage_enabled=mailbox_policy.get(
|
||||
"AdditionalStorageProvidersAvailable", True
|
||||
),
|
||||
)
|
||||
policies_data = self.powershell.get_mailbox_policy()
|
||||
if policies_data:
|
||||
if isinstance(policies_data, dict):
|
||||
policies_data = [policies_data]
|
||||
for policy in policies_data:
|
||||
if policy:
|
||||
mailbox_policies.append(
|
||||
MailboxPolicy(
|
||||
id=policy.get("Id", ""),
|
||||
additional_storage_enabled=policy.get(
|
||||
"AdditionalStorageProvidersAvailable", True
|
||||
),
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return mailboxes_policy
|
||||
return mailbox_policies
|
||||
|
||||
def _get_role_assignment_policies(self):
|
||||
logger.info("Microsoft365 - Getting role assignment policies...")
|
||||
|
||||
@@ -29,9 +29,11 @@ class Test_exchange_mailbox_policy_additional_storage_restricted:
|
||||
MailboxPolicy,
|
||||
)
|
||||
|
||||
exchange_client.mailbox_policy = MailboxPolicy(
|
||||
id="OwaMailboxPolicy-Default", additional_storage_enabled=False
|
||||
)
|
||||
exchange_client.mailbox_policies = [
|
||||
MailboxPolicy(
|
||||
id="OwaMailboxPolicy-Default", additional_storage_enabled=False
|
||||
)
|
||||
]
|
||||
|
||||
check = exchange_mailbox_policy_additional_storage_restricted()
|
||||
result = check.execute()
|
||||
@@ -40,10 +42,13 @@ class Test_exchange_mailbox_policy_additional_storage_restricted:
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Exchange mailbox policy restricts additional storage providers."
|
||||
== "Exchange mailbox policy 'OwaMailboxPolicy-Default' restricts additional storage providers."
|
||||
)
|
||||
assert result[0].resource == exchange_client.mailbox_policies[0].dict()
|
||||
assert (
|
||||
result[0].resource_name
|
||||
== "Exchange Mailbox Policy - OwaMailboxPolicy-Default"
|
||||
)
|
||||
assert result[0].resource == exchange_client.mailbox_policy.dict()
|
||||
assert result[0].resource_name == "Exchange Mailbox Policy"
|
||||
assert result[0].resource_id == "OwaMailboxPolicy-Default"
|
||||
assert result[0].location == "global"
|
||||
|
||||
@@ -72,9 +77,11 @@ class Test_exchange_mailbox_policy_additional_storage_restricted:
|
||||
MailboxPolicy,
|
||||
)
|
||||
|
||||
exchange_client.mailbox_policy = MailboxPolicy(
|
||||
id="OwaMailboxPolicy-Default", additional_storage_enabled=True
|
||||
)
|
||||
exchange_client.mailbox_policies = [
|
||||
MailboxPolicy(
|
||||
id="OwaMailboxPolicy-Default", additional_storage_enabled=True
|
||||
)
|
||||
]
|
||||
|
||||
check = exchange_mailbox_policy_additional_storage_restricted()
|
||||
result = check.execute()
|
||||
@@ -83,10 +90,13 @@ class Test_exchange_mailbox_policy_additional_storage_restricted:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Exchange mailbox policy allows additional storage providers."
|
||||
== "Exchange mailbox policy 'OwaMailboxPolicy-Default' allows additional storage providers."
|
||||
)
|
||||
assert result[0].resource == exchange_client.mailbox_policies[0].dict()
|
||||
assert (
|
||||
result[0].resource_name
|
||||
== "Exchange Mailbox Policy - OwaMailboxPolicy-Default"
|
||||
)
|
||||
assert result[0].resource == exchange_client.mailbox_policy.dict()
|
||||
assert result[0].resource_name == "Exchange Mailbox Policy"
|
||||
assert result[0].resource_id == "OwaMailboxPolicy-Default"
|
||||
assert result[0].location == "global"
|
||||
|
||||
@@ -94,7 +104,7 @@ class Test_exchange_mailbox_policy_additional_storage_restricted:
|
||||
exchange_client = mock.MagicMock()
|
||||
exchange_client.audited_tenant = "audited_tenant"
|
||||
exchange_client.audited_domain = DOMAIN
|
||||
exchange_client.mailbox_policy = None
|
||||
exchange_client.mailbox_policies = []
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
@@ -116,3 +126,57 @@ class Test_exchange_mailbox_policy_additional_storage_restricted:
|
||||
check = exchange_mailbox_policy_additional_storage_restricted()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_multiple_mailbox_policies_mixed_results(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_policy_additional_storage_restricted.exchange_mailbox_policy_additional_storage_restricted.exchange_client",
|
||||
new=exchange_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.exchange.exchange_mailbox_policy_additional_storage_restricted.exchange_mailbox_policy_additional_storage_restricted import (
|
||||
exchange_mailbox_policy_additional_storage_restricted,
|
||||
)
|
||||
from prowler.providers.m365.services.exchange.exchange_service import (
|
||||
MailboxPolicy,
|
||||
)
|
||||
|
||||
exchange_client.mailbox_policies = [
|
||||
MailboxPolicy(
|
||||
id="OwaMailboxPolicy-Default", additional_storage_enabled=False
|
||||
),
|
||||
MailboxPolicy(id="OWA-Policy-2", additional_storage_enabled=True),
|
||||
MailboxPolicy(id="OWA-Policy-3", additional_storage_enabled=False),
|
||||
]
|
||||
|
||||
check = exchange_mailbox_policy_additional_storage_restricted()
|
||||
result = check.execute()
|
||||
|
||||
# Should have 3 results, one for each policy
|
||||
assert len(result) == 3
|
||||
|
||||
# First policy (Default) should PASS
|
||||
assert result[0].status == "PASS"
|
||||
assert result[0].resource_id == "OwaMailboxPolicy-Default"
|
||||
assert "restricts additional storage providers" in result[0].status_extended
|
||||
|
||||
# Second policy should FAIL
|
||||
assert result[1].status == "FAIL"
|
||||
assert result[1].resource_id == "OWA-Policy-2"
|
||||
assert "allows additional storage providers" in result[1].status_extended
|
||||
|
||||
# Third policy should PASS
|
||||
assert result[2].status == "PASS"
|
||||
assert result[2].resource_id == "OWA-Policy-3"
|
||||
assert "restricts additional storage providers" in result[2].status_extended
|
||||
|
||||
@@ -7,7 +7,6 @@ from prowler.providers.m365.services.exchange.exchange_service import (
|
||||
ExternalMailConfig,
|
||||
MailboxAuditConfig,
|
||||
MailboxAuditProperties,
|
||||
MailboxPolicy,
|
||||
Organization,
|
||||
RoleAssignmentPolicy,
|
||||
TransportConfig,
|
||||
@@ -72,13 +71,6 @@ def mock_exchange_get_transport_config(_):
|
||||
)
|
||||
|
||||
|
||||
def mock_exchange_get_mailbox_policy(_):
|
||||
return MailboxPolicy(
|
||||
id="test",
|
||||
additional_storage_enabled=True,
|
||||
)
|
||||
|
||||
|
||||
def mock_exchange_get_role_assignment_policies(_):
|
||||
return [
|
||||
RoleAssignmentPolicy(
|
||||
@@ -272,13 +264,19 @@ class Test_Exchange_Service:
|
||||
exchange_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.services.exchange.exchange_service.Exchange._get_mailbox_policy",
|
||||
new=mock_exchange_get_mailbox_policy,
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.get_mailbox_policy",
|
||||
return_value=[
|
||||
{
|
||||
"Id": "test",
|
||||
"AdditionalStorageProvidersAvailable": True,
|
||||
}
|
||||
],
|
||||
)
|
||||
def test_get_mailbox_policy(self):
|
||||
def test_get_mailbox_policy(self, _mock_get_mailbox_policy):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online",
|
||||
return_value=True,
|
||||
),
|
||||
):
|
||||
exchange_client = Exchange(
|
||||
@@ -286,9 +284,35 @@ class Test_Exchange_Service:
|
||||
identity=M365IdentityInfo(tenant_domain=DOMAIN)
|
||||
)
|
||||
)
|
||||
mailbox_policy = exchange_client.mailbox_policy
|
||||
assert mailbox_policy.id == "test"
|
||||
assert mailbox_policy.additional_storage_enabled is True
|
||||
mailbox_policies = exchange_client.mailbox_policies
|
||||
assert len(mailbox_policies) == 1
|
||||
assert mailbox_policies[0].id == "test"
|
||||
assert mailbox_policies[0].additional_storage_enabled is True
|
||||
exchange_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.get_mailbox_policy",
|
||||
return_value={
|
||||
"Id": "test_single",
|
||||
"AdditionalStorageProvidersAvailable": False,
|
||||
},
|
||||
)
|
||||
def test_get_mailbox_policy_single_dict(self, _mock_get_mailbox_policy):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online",
|
||||
return_value=True,
|
||||
),
|
||||
):
|
||||
exchange_client = Exchange(
|
||||
set_mocked_m365_provider(
|
||||
identity=M365IdentityInfo(tenant_domain=DOMAIN)
|
||||
)
|
||||
)
|
||||
mailbox_policies = exchange_client.mailbox_policies
|
||||
assert len(mailbox_policies) == 1
|
||||
assert mailbox_policies[0].id == "test_single"
|
||||
assert mailbox_policies[0].additional_storage_enabled is False
|
||||
exchange_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
|
||||
Reference in New Issue
Block a user