mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 21:11:53 +00:00
fix(defender): enhance policies checks logic (#7666)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com> Co-authored-by: MrCloudSec <hello@mistercloudsec.com>
This commit is contained in:
committed by
GitHub
parent
16f2209d3f
commit
1a8df3bf18
@@ -525,6 +525,26 @@ class M365PowerShell(PowerShellSession):
|
||||
"Get-HostedContentFilterPolicy | ConvertTo-Json", json_parse=True
|
||||
)
|
||||
|
||||
def get_inbound_spam_filter_rule(self) -> dict:
|
||||
"""
|
||||
Get Inbound Spam Filter Rule.
|
||||
|
||||
Retrieves the current inbound spam filter rule settings for Exchange Online.
|
||||
|
||||
Returns:
|
||||
dict: Inbound spam filter rule settings in JSON format.
|
||||
|
||||
Example:
|
||||
>>> get_inbound_spam_filter_rule()
|
||||
{
|
||||
"Name": "Rule1",
|
||||
"State": "Enabled"
|
||||
}
|
||||
"""
|
||||
return self.execute(
|
||||
"Get-HostedContentFilterRule | ConvertTo-Json", json_parse=True
|
||||
)
|
||||
|
||||
def get_report_submission_policy(self) -> dict:
|
||||
"""
|
||||
Get Exchange Online Report Submission Policy.
|
||||
|
||||
+147
-29
@@ -23,37 +23,155 @@ class defender_antiphishing_policy_configured(Check):
|
||||
List[CheckReportM365]: A list of reports containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
for policy_name, policy in defender_client.antiphishing_policies.items():
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name="Defender Anti-Phishing Policy",
|
||||
resource_id=policy_name,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Anti-phishing policy {policy_name} is not properly configured."
|
||||
)
|
||||
|
||||
if (
|
||||
not policy.default
|
||||
and policy_name in defender_client.antiphising_rules
|
||||
and defender_client.antiphising_rules[policy_name].state.lower()
|
||||
== "enabled"
|
||||
) or policy.default:
|
||||
if (
|
||||
policy.spoof_intelligence
|
||||
and policy.spoof_intelligence_action.lower() == "quarantine"
|
||||
and policy.dmarc_reject_action.lower() == "quarantine"
|
||||
and policy.dmarc_quarantine_action.lower() == "quarantine"
|
||||
and policy.safety_tips
|
||||
and policy.unauthenticated_sender_action
|
||||
and policy.show_tag
|
||||
and policy.honor_dmarc_policy
|
||||
):
|
||||
if defender_client.antiphishing_policies:
|
||||
# Only Default Defender Anti-Phishing Policy exists since there are only anti phishing rules when there are custom policies
|
||||
if not defender_client.antiphishing_rules:
|
||||
# Get the only policy in the dictionary since there is only the default policy
|
||||
policy = next(iter(defender_client.antiphishing_policies.values()))
|
||||
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy.name,
|
||||
resource_id=policy.name,
|
||||
)
|
||||
|
||||
if self._is_policy_properly_configured(policy):
|
||||
# Case 1: Default policy exists and is properly configured
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Anti-phishing policy {policy_name} is properly configured and enabled."
|
||||
report.status_extended = f"{policy.name} is the only policy and it's properly configured in the default Defender Anti-Phishing Policy."
|
||||
else:
|
||||
# Case 5: Default policy exists but is not properly configured
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"{policy.name} is the only policy and it's not properly configured in the default Defender Anti-Phishing Policy."
|
||||
findings.append(report)
|
||||
|
||||
findings.append(report)
|
||||
# Multiple Defender Anti-Phishing Policies
|
||||
else:
|
||||
default_policy_well_configured = False
|
||||
|
||||
for (
|
||||
policy_name,
|
||||
policy,
|
||||
) in defender_client.antiphishing_policies.items():
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy_name,
|
||||
resource_id=policy_name,
|
||||
)
|
||||
if policy.default:
|
||||
if not self._is_policy_properly_configured(policy):
|
||||
# Case 4: Default policy is not properly configured and there are other policies
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"{policy_name} is not properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another well-configured Custom Policy."
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 2: Default policy is properly configured and there are other policies
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"{policy_name} is properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another bad-configured Custom Policy."
|
||||
default_policy_well_configured = True
|
||||
findings.append(report)
|
||||
else:
|
||||
if not self._is_policy_properly_configured(policy):
|
||||
included_resources = []
|
||||
|
||||
if defender_client.antiphishing_rules[policy.name].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.antiphishing_rules[policy.name].users)}"
|
||||
)
|
||||
if defender_client.antiphishing_rules[policy.name].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.antiphishing_rules[policy.name].groups)}"
|
||||
)
|
||||
if defender_client.antiphishing_rules[policy.name].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.antiphishing_rules[policy.name].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
# Case 3: Default policy is properly configured but other custom policies are not
|
||||
if default_policy_well_configured:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Anti-phishing policy {policy_name} is not properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.antiphishing_rules[policy.name].priority} (0 is the highest). "
|
||||
"However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
# Case 5: Default policy is not properly configured and other custom policies are not
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Anti-phishing policy {policy_name} is not properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.antiphishing_rules[policy.name].priority} (0 is the highest). "
|
||||
"Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
included_resources = []
|
||||
|
||||
if defender_client.antiphishing_rules[policy.name].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.antiphishing_rules[policy.name].users)}"
|
||||
)
|
||||
if defender_client.antiphishing_rules[policy.name].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.antiphishing_rules[policy.name].groups)}"
|
||||
)
|
||||
if defender_client.antiphishing_rules[policy.name].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.antiphishing_rules[policy.name].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
# Case 2: Default policy is properly configured and other custom policies are too
|
||||
if default_policy_well_configured:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Anti-phishing policy {policy_name} is properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.antiphishing_rules[policy.name].priority} (0 is the highest). "
|
||||
"Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
# Case 6: Default policy is not properly configured but other custom policies are
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Anti-phishing policy {policy_name} is properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.antiphishing_rules[policy.name].priority} (0 is the highest). "
|
||||
"However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
def _is_policy_properly_configured(self, policy) -> bool:
|
||||
"""
|
||||
Check if a policy is properly configured according to best practices.
|
||||
|
||||
Args:
|
||||
policy: The anti-phishing policy to check.
|
||||
|
||||
Returns:
|
||||
bool: True if the policy is properly configured, False otherwise.
|
||||
"""
|
||||
return (
|
||||
(
|
||||
policy.default
|
||||
or defender_client.antiphishing_rules[policy.name].state.lower()
|
||||
== "enabled"
|
||||
)
|
||||
and policy.spoof_intelligence
|
||||
and policy.spoof_intelligence_action.lower() == "quarantine"
|
||||
and policy.dmarc_reject_action.lower() == "quarantine"
|
||||
and policy.dmarc_quarantine_action.lower() == "quarantine"
|
||||
and policy.safety_tips
|
||||
and policy.unauthenticated_sender_action
|
||||
and policy.show_tag
|
||||
and policy.honor_dmarc_policy
|
||||
)
|
||||
|
||||
+147
-29
@@ -6,8 +6,7 @@ from prowler.providers.m365.services.defender.defender_client import defender_cl
|
||||
|
||||
class defender_antispam_outbound_policy_configured(Check):
|
||||
"""
|
||||
Check if the Exchange Online Spam Policies are configured to notify administrators
|
||||
when a sender is blocked for sending spam emails.
|
||||
Check if the outbound spam policy is established and properly configured in the Defender service.
|
||||
|
||||
Attributes:
|
||||
metadata: Metadata associated with the check (inherited from Check).
|
||||
@@ -15,40 +14,159 @@ class defender_antispam_outbound_policy_configured(Check):
|
||||
|
||||
def execute(self) -> List[CheckReportM365]:
|
||||
"""
|
||||
Execute the check to verify if the Exchange Online Spam Policies notify administrators
|
||||
when a sender is blocked for sending spam emails.
|
||||
Execute the check to verify if an outbound spam policy is established and properly configured.
|
||||
|
||||
This method checks the Defender outbound spam policies to ensure they are configured
|
||||
according to best practices.
|
||||
|
||||
Returns:
|
||||
List[CheckReportM365]: A list of reports containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
for policy_name, policy in defender_client.outbound_spam_policies.items():
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name="Defender Outbound Spam Policy",
|
||||
resource_id=policy_name,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Outbound Spam Policy {policy_name} is not properly configured."
|
||||
)
|
||||
|
||||
if (
|
||||
not policy.default
|
||||
and policy_name in defender_client.outbound_spam_rules
|
||||
and defender_client.outbound_spam_rules[policy_name].state.lower()
|
||||
== "enabled"
|
||||
) or policy.default:
|
||||
if (
|
||||
policy.notify_limit_exceeded
|
||||
and policy.notify_sender_blocked
|
||||
and policy.notify_limit_exceeded_addresses
|
||||
and policy.notify_sender_blocked_addresses
|
||||
):
|
||||
if defender_client.outbound_spam_policies:
|
||||
# Only Default Defender Outbound Spam Policy
|
||||
if not defender_client.outbound_spam_rules:
|
||||
# Get the only policy in the dictionary
|
||||
policy = next(iter(defender_client.outbound_spam_policies.values()))
|
||||
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy.name,
|
||||
resource_id=policy.name,
|
||||
)
|
||||
|
||||
if self._is_policy_properly_configured(policy):
|
||||
# Case 1: Default policy exists and is properly configured
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Outbound Spam Policy {policy_name} is properly configured and enabled."
|
||||
report.status_extended = f"{policy.name} is the only policy and it's properly configured in the default Defender Outbound Spam Policy."
|
||||
else:
|
||||
# Case 5: Default policy exists but is not properly configured
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"{policy.name} is the only policy and it's not properly configured in the default Defender Outbound Spam Policy."
|
||||
findings.append(report)
|
||||
|
||||
findings.append(report)
|
||||
# Multiple Defender Outbound Spam Policies
|
||||
else:
|
||||
default_policy_well_configured = False
|
||||
|
||||
for (
|
||||
policy_name,
|
||||
policy,
|
||||
) in defender_client.outbound_spam_policies.items():
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy_name,
|
||||
resource_id=policy_name,
|
||||
)
|
||||
if policy.default:
|
||||
if not self._is_policy_properly_configured(policy):
|
||||
# Case 4: Default policy is not properly configured and there are other policies
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"{policy_name} is not properly configured in the default Defender Outbound Spam Policy, but could be overridden by another well-configured Custom Policy."
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 2: Default policy is properly configured and there are other policies
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"{policy_name} is properly configured in the default Defender Outbound Spam Policy, but could be overridden by another bad-configured Custom Policy."
|
||||
default_policy_well_configured = True
|
||||
findings.append(report)
|
||||
else:
|
||||
if not self._is_policy_properly_configured(policy):
|
||||
included_resources = []
|
||||
|
||||
if defender_client.outbound_spam_rules[policy.name].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.outbound_spam_rules[policy.name].users)}"
|
||||
)
|
||||
if defender_client.outbound_spam_rules[policy.name].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.outbound_spam_rules[policy.name].groups)}"
|
||||
)
|
||||
if defender_client.outbound_spam_rules[policy.name].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.outbound_spam_rules[policy.name].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
# Case 3: Default policy is properly configured but other custom policies are not
|
||||
if default_policy_well_configured:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Outbound Spam policy {policy_name} is not properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
|
||||
"However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
# Case 5: Default policy is not properly configured and other custom policies are not
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Outbound Spam policy {policy_name} is not properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
|
||||
"Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
included_resources = []
|
||||
|
||||
if defender_client.outbound_spam_rules[policy.name].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.outbound_spam_rules[policy.name].users)}"
|
||||
)
|
||||
if defender_client.outbound_spam_rules[policy.name].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.outbound_spam_rules[policy.name].groups)}"
|
||||
)
|
||||
if defender_client.outbound_spam_rules[policy.name].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.outbound_spam_rules[policy.name].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
# Case 2: Default policy is properly configured and other custom policies are too
|
||||
if default_policy_well_configured:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Outbound Spam policy {policy_name} is properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
|
||||
"Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
# Case 6: Default policy is not properly configured but other custom policies are
|
||||
else:
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Outbound Spam policy {policy_name} is properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
|
||||
"However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
def _is_policy_properly_configured(self, policy) -> bool:
|
||||
"""
|
||||
Check if a policy is properly configured according to best practices.
|
||||
|
||||
Args:
|
||||
policy: The outbound spam policy to check.
|
||||
|
||||
Returns:
|
||||
bool: True if the policy is properly configured, False otherwise.
|
||||
"""
|
||||
return (
|
||||
(
|
||||
policy.default
|
||||
or defender_client.outbound_spam_rules[policy.name].state.lower()
|
||||
== "enabled"
|
||||
)
|
||||
and policy.notify_limit_exceeded
|
||||
and policy.notify_sender_blocked
|
||||
and policy.notify_limit_exceeded_addresses
|
||||
and policy.notify_sender_blocked_addresses
|
||||
)
|
||||
|
||||
+142
-20
@@ -20,28 +20,150 @@ class defender_antispam_outbound_policy_forwarding_disabled(Check):
|
||||
List[CheckReportM365]: A list of reports containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
for policy_name, policy in defender_client.outbound_spam_policies.items():
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name="Defender Outbound Spam Policy",
|
||||
resource_id=policy_name,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Outbound Spam Policy {policy_name} does allow mail forwarding."
|
||||
)
|
||||
|
||||
if (
|
||||
not policy.default
|
||||
and policy_name in defender_client.outbound_spam_rules
|
||||
and defender_client.outbound_spam_rules[policy_name].state.lower()
|
||||
== "enabled"
|
||||
) or policy.default:
|
||||
if not policy.auto_forwarding_mode:
|
||||
if defender_client.outbound_spam_policies:
|
||||
# Only Default Defender Outbound Spam Policy exists
|
||||
if not defender_client.outbound_spam_rules:
|
||||
policy = next(iter(defender_client.outbound_spam_policies.values()))
|
||||
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy.name,
|
||||
resource_id=policy.name,
|
||||
)
|
||||
|
||||
if self._is_forwarding_disabled(policy):
|
||||
# Case 1: Default policy exists and has forwarding disabled
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Outbound Spam Policy {policy_name} does not allow mail forwarding."
|
||||
report.status_extended = f"{policy.name} is the only policy and mail forwarding is disabled."
|
||||
else:
|
||||
# Case 5: Default policy exists but allows forwarding
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"{policy.name} is the only policy and mail forwarding is allowed."
|
||||
findings.append(report)
|
||||
|
||||
findings.append(report)
|
||||
# Multiple Defender Outbound Spam Policies exist
|
||||
else:
|
||||
default_policy_well_configured = False
|
||||
|
||||
for (
|
||||
policy_name,
|
||||
policy,
|
||||
) in defender_client.outbound_spam_policies.items():
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy_name,
|
||||
resource_id=policy_name,
|
||||
)
|
||||
|
||||
if policy.default:
|
||||
if not self._is_forwarding_disabled(policy):
|
||||
# Case 4: Default policy allows forwarding and there are other policies
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"{policy_name} is the default policy and mail forwarding is allowed, "
|
||||
"but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 2: Default policy disables forwarding and there are other policies
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"{policy_name} is the default policy and mail forwarding is disabled, "
|
||||
"but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
default_policy_well_configured = True
|
||||
findings.append(report)
|
||||
else:
|
||||
if not self._is_forwarding_disabled(policy):
|
||||
included_resources = []
|
||||
|
||||
if defender_client.outbound_spam_rules[policy.name].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.outbound_spam_rules[policy.name].users)}"
|
||||
)
|
||||
if defender_client.outbound_spam_rules[policy.name].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.outbound_spam_rules[policy.name].groups)}"
|
||||
)
|
||||
if defender_client.outbound_spam_rules[policy.name].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.outbound_spam_rules[policy.name].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 3: Default policy disables forwarding but custom one doesn't
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Outbound Spam policy {policy_name} allows mail forwarding and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
|
||||
"However, the default policy disables mail forwarding, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 5: Neither default nor custom policies disable forwarding
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Outbound Spam policy {policy_name} allows mail forwarding and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
|
||||
"Also, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
included_resources = []
|
||||
|
||||
if defender_client.outbound_spam_rules[policy.name].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.outbound_spam_rules[policy.name].users)}"
|
||||
)
|
||||
if defender_client.outbound_spam_rules[policy.name].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.outbound_spam_rules[policy.name].groups)}"
|
||||
)
|
||||
if defender_client.outbound_spam_rules[policy.name].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.outbound_spam_rules[policy.name].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 2: Both default and custom policies disable forwarding
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Outbound Spam policy {policy_name} disables mail forwarding and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
|
||||
"Also, the default policy disables mail forwarding, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 6: Default policy allows forwarding, custom policy disables it
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Outbound Spam policy {policy_name} disables mail forwarding and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.outbound_spam_rules[policy.name].priority} (0 is the highest). "
|
||||
"However, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
def _is_forwarding_disabled(self, policy) -> bool:
|
||||
"""
|
||||
Check if mail forwarding is disabled in the policy.
|
||||
|
||||
Args:
|
||||
policy: The outbound spam policy to check.
|
||||
|
||||
Returns:
|
||||
bool: True if mail forwarding is disabled, False otherwise.
|
||||
"""
|
||||
return (
|
||||
policy.default
|
||||
or defender_client.outbound_spam_rules[policy.name].state.lower()
|
||||
== "enabled"
|
||||
) and not policy.auto_forwarding_mode
|
||||
|
||||
+156
-13
@@ -23,20 +23,163 @@ class defender_antispam_policy_inbound_no_allowed_domains(Check):
|
||||
List[CheckReportM365]: A list of reports containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
for policy in defender_client.inbound_spam_policies:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name="Defender Inbound Spam Policy",
|
||||
resource_id=policy.identity,
|
||||
)
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Inbound anti-spam policy {policy.identity} does not contain allowed domains."
|
||||
|
||||
if policy.allowed_sender_domains:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Inbound anti-spam policy {policy.identity} contains allowed domains: {policy.allowed_sender_domains}."
|
||||
if defender_client.inbound_spam_policies:
|
||||
# Only Default Defender Inbound Spam Policy exists
|
||||
if not defender_client.inbound_spam_rules:
|
||||
policy = defender_client.inbound_spam_policies[0]
|
||||
|
||||
findings.append(report)
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy.identity,
|
||||
resource_id=policy.identity,
|
||||
)
|
||||
|
||||
if self._has_no_allowed_domains(policy):
|
||||
# Case 1: Default policy exists and has no allowed domains
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"{policy.identity} is the only policy and it does not contain allowed domains."
|
||||
else:
|
||||
# Case 5: Default policy exists but contains allowed domains
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"{policy.identity} is the only policy and it contains allowed domains: {', '.join(policy.allowed_sender_domains)}."
|
||||
findings.append(report)
|
||||
|
||||
# Multiple Defender Inbound Spam Policies exist
|
||||
else:
|
||||
default_policy_well_configured = False
|
||||
|
||||
for policy in defender_client.inbound_spam_policies:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy.identity,
|
||||
resource_id=policy.identity,
|
||||
)
|
||||
|
||||
if policy.default:
|
||||
if not self._has_no_allowed_domains(policy):
|
||||
# Case 4: Default policy contains allowed domains
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"{policy.identity} is the default policy and it contains allowed domains: {', '.join(policy.allowed_sender_domains)}, "
|
||||
"but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 2: Default policy has no allowed domains and there are other policies
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"{policy.identity} is the default policy and it does not contain allowed domains, "
|
||||
"but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
default_policy_well_configured = True
|
||||
findings.append(report)
|
||||
else:
|
||||
if not self._has_no_allowed_domains(policy):
|
||||
included_resources = []
|
||||
|
||||
if defender_client.inbound_spam_rules[
|
||||
policy.identity
|
||||
].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.inbound_spam_rules[policy.identity].users)}"
|
||||
)
|
||||
if defender_client.inbound_spam_rules[
|
||||
policy.identity
|
||||
].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.inbound_spam_rules[policy.identity].groups)}"
|
||||
)
|
||||
if defender_client.inbound_spam_rules[
|
||||
policy.identity
|
||||
].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.inbound_spam_rules[policy.identity].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
priority = defender_client.inbound_spam_rules[
|
||||
policy.identity
|
||||
].priority
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 3: Default policy has no allowed domains but custom one does
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Inbound Spam policy {policy.identity} contains allowed domains and includes {included_resources_str}, "
|
||||
f"with priority {priority} (0 is the highest). However, the default policy does not contain allowed domains, "
|
||||
"so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
else:
|
||||
# Case 5: Neither default nor custom policies are correctly configured
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Inbound Spam policy {policy.identity} contains allowed domains and includes {included_resources_str}, "
|
||||
f"with priority {priority} (0 is the highest). Also, the default policy contains allowed domains, "
|
||||
"so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
included_resources = []
|
||||
|
||||
if defender_client.inbound_spam_rules[
|
||||
policy.identity
|
||||
].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.inbound_spam_rules[policy.identity].users)}"
|
||||
)
|
||||
if defender_client.inbound_spam_rules[
|
||||
policy.identity
|
||||
].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.inbound_spam_rules[policy.identity].groups)}"
|
||||
)
|
||||
if defender_client.inbound_spam_rules[
|
||||
policy.identity
|
||||
].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.inbound_spam_rules[policy.identity].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
priority = defender_client.inbound_spam_rules[
|
||||
policy.identity
|
||||
].priority
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 2: Both default and custom policies do not contain allowed domains
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Inbound Spam policy {policy.identity} does not contain allowed domains and includes {included_resources_str}, "
|
||||
f"with priority {priority} (0 is the highest). Also, the default policy does not contain allowed domains, "
|
||||
"so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
else:
|
||||
# Case 6: Default policy contains allowed domains, custom policy does not
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Inbound Spam policy {policy.identity} does not contain allowed domains and includes {included_resources_str}, "
|
||||
f"with priority {priority} (0 is the highest). However, the default policy contains allowed domains, "
|
||||
"so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
def _has_no_allowed_domains(self, policy) -> bool:
|
||||
"""
|
||||
Check if the policy has no allowed domains.
|
||||
|
||||
Args:
|
||||
policy: The inbound spam policy to check.
|
||||
|
||||
Returns:
|
||||
bool: True if the policy has no allowed domains, False otherwise.
|
||||
"""
|
||||
return (
|
||||
policy.default
|
||||
or defender_client.inbound_spam_rules[policy.identity].state.lower()
|
||||
== "enabled"
|
||||
) and not policy.allowed_sender_domains
|
||||
|
||||
+119
-20
@@ -16,39 +16,138 @@ class defender_malware_policy_common_attachments_filter_enabled(Check):
|
||||
"""
|
||||
Execute the check to verify if the Common Attachment Types Filter is enabled.
|
||||
|
||||
This method checks the Defender anti-malware policy to determine if the
|
||||
This method checks the Defender anti-malware policies to determine if the
|
||||
Common Attachment Types Filter is enabled.
|
||||
|
||||
Returns:
|
||||
List[CheckReportM365]: A list of reports containing the result of the check.
|
||||
"""
|
||||
findings = []
|
||||
if not defender_client.malware_policies:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource={},
|
||||
resource_name="Defender Malware Policy",
|
||||
resource_id="defenderMalwarePolicy",
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "Common Attachment Types Filter is not enabled."
|
||||
findings.append(report)
|
||||
else:
|
||||
for policy in defender_client.malware_policies:
|
||||
|
||||
if defender_client.malware_policies:
|
||||
# Only Default Defender Malware Policy exists
|
||||
if not defender_client.malware_rules:
|
||||
policy = defender_client.malware_policies[0]
|
||||
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name="Defender Malware Policy",
|
||||
resource_id="defenderMalwarePolicy",
|
||||
resource_name=policy.identity,
|
||||
resource_id=policy.identity,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Common Attachment Types Filter is not enabled in anti-malware policy {policy.identity}."
|
||||
|
||||
if policy.enable_file_filter:
|
||||
# Case 1: Default policy exists and has the setting enabled
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Common Attachment Types Filter is enabled in anti-malware policy {policy.identity}."
|
||||
break
|
||||
report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is enabled."
|
||||
else:
|
||||
# Case 5: Default policy exists but doesn't have the setting enabled
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is not enabled."
|
||||
findings.append(report)
|
||||
|
||||
findings.append(report)
|
||||
# Multiple Defender Malware Policies exist
|
||||
else:
|
||||
default_policy_well_configured = False
|
||||
|
||||
for policy in defender_client.malware_policies:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy.identity,
|
||||
resource_id=policy.identity,
|
||||
)
|
||||
|
||||
if policy.is_default:
|
||||
if not policy.enable_file_filter:
|
||||
# Case 4: Default policy doesn't have the setting enabled and there are other policies
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"{policy.identity} is the default policy and Common Attachment Types Filter is not enabled, "
|
||||
"but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 2: Default policy has the setting enabled and there are other policies
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"{policy.identity} is the default policy and Common Attachment Types Filter is enabled, "
|
||||
"but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
default_policy_well_configured = True
|
||||
findings.append(report)
|
||||
else:
|
||||
if not policy.enable_file_filter:
|
||||
included_resources = []
|
||||
|
||||
if defender_client.malware_rules[policy.identity].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 3: Default policy enables the setting but custom one doesn't
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} does not enable Common Attachment Types Filter and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"However, the default policy enables the filter, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 5: Neither default nor custom policies enable the setting
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} does not enable Common Attachment Types Filter and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"Also, the default policy does not enable the filter, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
included_resources = []
|
||||
|
||||
if defender_client.malware_rules[policy.identity].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 2: Both default and custom policies enable the setting
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} enables Common Attachment Types Filter and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"Also, the default policy enables the filter, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 6: Default policy doesn't enable the setting, but custom policy does
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} enables Common Attachment Types Filter and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"However, the default policy does not enable the filter, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
+159
-48
@@ -14,17 +14,16 @@ class defender_malware_policy_comprehensive_attachments_filter_applied(Check):
|
||||
|
||||
def execute(self) -> List[CheckReportM365]:
|
||||
"""
|
||||
Executes the check to determine if the Common Attachment Types Filter is enabled.
|
||||
Executes the check to determine if the Common Attachment Types Filter is properly configured.
|
||||
|
||||
This method evaluates the Defender anti-malware policy to ensure it is enabled and the
|
||||
Common Attachment Types Filter is active and applied to the recommended file types.
|
||||
This method evaluates the Defender anti-malware policies to ensure the filter is enabled and applied
|
||||
to all recommended file types.
|
||||
|
||||
Returns:
|
||||
List[CheckReportM365]: A list of reports with the results of the check.
|
||||
"""
|
||||
findings = []
|
||||
|
||||
# Default to Microsoft-recommended common file types
|
||||
default_recommended_extensions = [
|
||||
"ace",
|
||||
"ani",
|
||||
@@ -81,63 +80,175 @@ class defender_malware_policy_comprehensive_attachments_filter_applied(Check):
|
||||
"z",
|
||||
]
|
||||
|
||||
# Load extensions from audit_config (user config), fallback to default
|
||||
recommended_extensions = defender_client.audit_config.get(
|
||||
"recommended_blocked_file_types", default_recommended_extensions
|
||||
)
|
||||
|
||||
if not defender_client.malware_policies:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource={},
|
||||
resource_name="Defender Malware Policy",
|
||||
resource_id="defenderMalwarePolicy",
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "Common Attachment Types Filter is not enabled."
|
||||
findings.append(report)
|
||||
else:
|
||||
for policy in defender_client.malware_policies:
|
||||
if defender_client.malware_policies:
|
||||
# Only Default Defender Malware Policy exists
|
||||
if not defender_client.malware_rules:
|
||||
policy = defender_client.malware_policies[0]
|
||||
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name="Defender Malware Policy",
|
||||
resource_id="defenderMalwarePolicy",
|
||||
resource_name=policy.identity,
|
||||
resource_id=policy.identity,
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"Common Attachment Types Filter is not properly configured in anti-malware policy {policy.identity}."
|
||||
|
||||
if not policy.enable_file_filter:
|
||||
report.status_extended = f"Common Attachment Types Filter is not enabled in anti-malware policy {policy.identity}."
|
||||
break
|
||||
if self._is_filter_properly_configured(policy, recommended_extensions):
|
||||
# Case 1: Default policy exists and has filter properly configured
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is properly configured."
|
||||
else:
|
||||
# Case 5: Default policy exists but doesn't have filter properly configured
|
||||
missing = self._get_missing_extensions(
|
||||
policy, recommended_extensions
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"{policy.identity} is the only policy and Common Attachment Types Filter is not properly configured. Missing recommended file types: {', '.join(missing)}."
|
||||
findings.append(report)
|
||||
|
||||
if (
|
||||
not policy.is_default
|
||||
and policy.identity in defender_client.malware_rules
|
||||
) or policy.is_default:
|
||||
if (
|
||||
not policy.is_default
|
||||
and defender_client.malware_rules[policy.identity].state.lower()
|
||||
== "enabled"
|
||||
) or policy.is_default:
|
||||
blocked_extensions = [ext.lower() for ext in policy.file_types]
|
||||
missing = [
|
||||
ext
|
||||
for ext in recommended_extensions
|
||||
if ext.lower() not in blocked_extensions
|
||||
]
|
||||
# Multiple Defender Malware Policies exist
|
||||
else:
|
||||
default_policy_well_configured = False
|
||||
|
||||
if missing:
|
||||
report.status_extended = f"Common Attachment Types Filter is enabled in anti-malware policy {policy.identity}, but the following recommended file types are missing: {', '.join(missing)}."
|
||||
break
|
||||
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"Common Attachment Types Filter is enabled in anti-malware policy {policy.identity}, the policy is enabled and the filter is applied to the recommended file types."
|
||||
for policy in defender_client.malware_policies:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy.identity,
|
||||
resource_id=policy.identity,
|
||||
)
|
||||
|
||||
if policy.is_default:
|
||||
if not self._is_filter_properly_configured(
|
||||
policy, recommended_extensions
|
||||
):
|
||||
# Case 4: Default policy is not properly configured
|
||||
missing = self._get_missing_extensions(
|
||||
policy, recommended_extensions
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"{policy.identity} is the default policy and Common Attachment Types Filter is not properly configured, "
|
||||
f"but it could be overridden by another well-configured Custom Policy. Missing recommended file types: {', '.join(missing)}."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 2: Default policy is properly configured
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"{policy.identity} is the default policy and Common Attachment Types Filter is properly configured, "
|
||||
"but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
default_policy_well_configured = True
|
||||
findings.append(report)
|
||||
else:
|
||||
report.status_extended = f"Common Attachment Types Filter is enabled in anti-malware policy {policy.identity}, but the policy is disabled."
|
||||
break
|
||||
if not self._is_filter_properly_configured(
|
||||
policy, recommended_extensions
|
||||
):
|
||||
included_resources = []
|
||||
|
||||
findings.append(report)
|
||||
if defender_client.malware_rules[policy.identity].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
missing = self._get_missing_extensions(
|
||||
policy, recommended_extensions
|
||||
)
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 3: Default policy is configured, custom one isn't
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
f"Missing recommended file types: {', '.join(missing)}. "
|
||||
"However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 5: Neither default nor custom policy is properly configured
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
f"Missing recommended file types: {', '.join(missing)}. "
|
||||
"Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
included_resources = []
|
||||
|
||||
if defender_client.malware_rules[policy.identity].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 2: Both default and custom policies are properly configured
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 6: Default policy not configured, custom policy is
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
def _is_filter_properly_configured(self, policy, recommended_extensions) -> bool:
|
||||
if not policy.enable_file_filter:
|
||||
return False
|
||||
|
||||
if (
|
||||
not policy.is_default
|
||||
and policy.identity in defender_client.malware_rules
|
||||
and defender_client.malware_rules[policy.identity].state.lower()
|
||||
!= "enabled"
|
||||
):
|
||||
return False
|
||||
|
||||
blocked_extensions = [ext.lower() for ext in policy.file_types]
|
||||
return all(ext.lower() in blocked_extensions for ext in recommended_extensions)
|
||||
|
||||
def _get_missing_extensions(self, policy, recommended_extensions) -> List[str]:
|
||||
if not policy.enable_file_filter:
|
||||
return recommended_extensions
|
||||
|
||||
blocked_extensions = [ext.lower() for ext in policy.file_types]
|
||||
return [
|
||||
ext
|
||||
for ext in recommended_extensions
|
||||
if ext.lower() not in blocked_extensions
|
||||
]
|
||||
|
||||
+136
-31
@@ -16,47 +16,152 @@ class defender_malware_policy_notifications_internal_users_malware_enabled(Check
|
||||
"""
|
||||
Execute the check to verify if notifications for internal users sending malware are enabled.
|
||||
|
||||
This method checks the Defender anti-malware policy to determine if notifications for internal users
|
||||
sending malware are enabled.
|
||||
This method evaluates the Defender anti-malware policies to ensure internal sender notifications
|
||||
are properly configured.
|
||||
|
||||
Returns:
|
||||
List[CheckReportM365]: A list of reports containing the result of the check.
|
||||
List[CheckReportM365]: A list of reports with the results of the check.
|
||||
"""
|
||||
findings = []
|
||||
if not defender_client.malware_policies:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource={},
|
||||
resource_name="Defender Malware Policy",
|
||||
resource_id="defenderMalwarePolicy",
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
"Notifications for internal users sending malware are not enabled."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
for policy in defender_client.malware_policies:
|
||||
|
||||
if defender_client.malware_policies:
|
||||
# Only Default Defender Malware Policy exists
|
||||
if not defender_client.malware_rules:
|
||||
policy = defender_client.malware_policies[0]
|
||||
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name="Defender Malware Policy",
|
||||
resource_id="defenderMalwarePolicy",
|
||||
)
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
"Notifications for internal users sending malware are not enabled."
|
||||
resource_name=policy.identity,
|
||||
resource_id=policy.identity,
|
||||
)
|
||||
|
||||
if policy.enable_internal_sender_admin_notifications:
|
||||
if policy.internal_sender_admin_address:
|
||||
report.status = "PASS"
|
||||
report.status_extended = "Notifications for internal users sending malware are enabled."
|
||||
break
|
||||
if self._are_notifications_enabled(policy):
|
||||
# Case 1: Default policy exists and has notifications enabled
|
||||
report.status = "PASS"
|
||||
report.status_extended = f"{policy.identity} is the only policy and notifications for internal users sending malware are enabled."
|
||||
else:
|
||||
# Case 5: Default policy exists but doesn't have notifications enabled
|
||||
report.status = "FAIL"
|
||||
report.status_extended = f"{policy.identity} is the only policy and notifications for internal users sending malware are not enabled."
|
||||
findings.append(report)
|
||||
|
||||
# Multiple Defender Malware Policies exist
|
||||
else:
|
||||
default_policy_well_configured = False
|
||||
|
||||
for policy in defender_client.malware_policies:
|
||||
report = CheckReportM365(
|
||||
metadata=self.metadata(),
|
||||
resource=policy,
|
||||
resource_name=policy.identity,
|
||||
resource_id=policy.identity,
|
||||
)
|
||||
|
||||
if policy.is_default:
|
||||
if not self._are_notifications_enabled(policy):
|
||||
# Case 4: Default policy not configured
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"{policy.identity} is the default policy and notifications for internal users sending malware are not enabled, "
|
||||
"but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 2: Default policy is properly configured
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"{policy.identity} is the default policy and notifications for internal users sending malware are enabled, "
|
||||
"but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
default_policy_well_configured = True
|
||||
findings.append(report)
|
||||
else:
|
||||
report.status = "FAIL"
|
||||
report.status_extended = "Notifications for internal users sending malware are enabled, but no email addresses are configured."
|
||||
if not self._are_notifications_enabled(policy):
|
||||
included_resources = []
|
||||
|
||||
findings.append(report)
|
||||
if defender_client.malware_rules[policy.identity].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 3: Default policy is configured, custom one isn't
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 5: Neither default nor custom policy is properly configured
|
||||
report.status = "FAIL"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} is not properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
included_resources = []
|
||||
|
||||
if defender_client.malware_rules[policy.identity].users:
|
||||
included_resources.append(
|
||||
f"users: {', '.join(defender_client.malware_rules[policy.identity].users)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].groups:
|
||||
included_resources.append(
|
||||
f"groups: {', '.join(defender_client.malware_rules[policy.identity].groups)}"
|
||||
)
|
||||
if defender_client.malware_rules[policy.identity].domains:
|
||||
included_resources.append(
|
||||
f"domains: {', '.join(defender_client.malware_rules[policy.identity].domains)}"
|
||||
)
|
||||
|
||||
included_resources_str = "; ".join(included_resources)
|
||||
|
||||
if default_policy_well_configured:
|
||||
# Case 2: Both default and custom policies are properly configured
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
else:
|
||||
# Case 6: Default policy not configured, custom policy is
|
||||
report.status = "PASS"
|
||||
report.status_extended = (
|
||||
f"Custom Malware policy {policy.identity} is properly configured and includes {included_resources_str}, "
|
||||
f"with priority {defender_client.malware_rules[policy.identity].priority} (0 is the highest). "
|
||||
"However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
findings.append(report)
|
||||
|
||||
return findings
|
||||
|
||||
def _are_notifications_enabled(self, policy) -> bool:
|
||||
if (
|
||||
not policy.is_default
|
||||
and policy.identity in defender_client.malware_rules
|
||||
and defender_client.malware_rules[policy.identity].state.lower()
|
||||
!= "enabled"
|
||||
):
|
||||
return False
|
||||
|
||||
return (
|
||||
policy.enable_internal_sender_admin_notifications
|
||||
and policy.internal_sender_admin_address
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import List
|
||||
from typing import List, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
@@ -14,10 +14,11 @@ class Defender(M365Service):
|
||||
self.outbound_spam_policies = {}
|
||||
self.outbound_spam_rules = {}
|
||||
self.antiphishing_policies = {}
|
||||
self.antiphising_rules = {}
|
||||
self.antiphishing_rules = {}
|
||||
self.connection_filter_policy = None
|
||||
self.dkim_configurations = []
|
||||
self.inbound_spam_policies = []
|
||||
self.inbound_spam_rules = {}
|
||||
self.report_submission_policy = None
|
||||
if self.powershell:
|
||||
self.powershell.connect_exchange_online()
|
||||
@@ -25,11 +26,12 @@ class Defender(M365Service):
|
||||
self.malware_rules = self._get_malware_filter_rule()
|
||||
self.outbound_spam_policies = self._get_outbound_spam_filter_policy()
|
||||
self.outbound_spam_rules = self._get_outbound_spam_filter_rule()
|
||||
self.antiphishing_policies = self._get_antiphising_policy()
|
||||
self.antiphising_rules = self._get_antiphising_rules()
|
||||
self.antiphishing_policies = self._get_antiphishing_policy()
|
||||
self.antiphishing_rules = self._get_antiphishing_rules()
|
||||
self.connection_filter_policy = self._get_connection_filter_policy()
|
||||
self.dkim_configurations = self._get_dkim_config()
|
||||
self.inbound_spam_policies = self._get_inbound_spam_filter_policy()
|
||||
self.inbound_spam_rules = self._get_inbound_spam_filter_rule()
|
||||
self.report_submission_policy = self._get_report_submission_policy()
|
||||
self.powershell.close()
|
||||
|
||||
@@ -44,7 +46,7 @@ class Defender(M365Service):
|
||||
if policy:
|
||||
malware_policies.append(
|
||||
MalwarePolicy(
|
||||
enable_file_filter=policy.get("EnableFileFilter", True),
|
||||
enable_file_filter=policy.get("EnableFileFilter", False),
|
||||
identity=policy.get("Identity", ""),
|
||||
enable_internal_sender_admin_notifications=policy.get(
|
||||
"EnableInternalSenderAdminNotifications", False
|
||||
@@ -56,6 +58,7 @@ class Defender(M365Service):
|
||||
is_default=policy.get("IsDefault", False),
|
||||
)
|
||||
)
|
||||
malware_policies.sort(key=lambda x: x.is_default, reverse=True)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
@@ -73,6 +76,10 @@ class Defender(M365Service):
|
||||
if rule:
|
||||
malware_rules[rule.get("Name", "")] = MalwareRule(
|
||||
state=rule.get("State", ""),
|
||||
priority=rule.get("Priority", 0),
|
||||
users=rule.get("SentTo", None),
|
||||
groups=rule.get("SentToMemberOf", None),
|
||||
domains=rule.get("RecipientDomainIs", None),
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
@@ -80,7 +87,7 @@ class Defender(M365Service):
|
||||
)
|
||||
return malware_rules
|
||||
|
||||
def _get_antiphising_policy(self):
|
||||
def _get_antiphishing_policy(self):
|
||||
logger.info("Microsoft365 - Getting Defender antiphishing policy...")
|
||||
antiphishing_policies = {}
|
||||
try:
|
||||
@@ -90,6 +97,7 @@ class Defender(M365Service):
|
||||
for policy in antiphishing_policy:
|
||||
if policy:
|
||||
antiphishing_policies[policy.get("Name", "")] = AntiphishingPolicy(
|
||||
name=policy.get("Name", ""),
|
||||
spoof_intelligence=policy.get("EnableSpoofIntelligence", True),
|
||||
spoof_intelligence_action=policy.get(
|
||||
"AuthenticationFailAction", ""
|
||||
@@ -104,13 +112,21 @@ class Defender(M365Service):
|
||||
honor_dmarc_policy=policy.get("HonorDmarcPolicy", True),
|
||||
default=policy.get("IsDefault", False),
|
||||
)
|
||||
|
||||
antiphishing_policies = dict(
|
||||
sorted(
|
||||
antiphishing_policies.items(),
|
||||
key=lambda item: item[1].default,
|
||||
reverse=True,
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return antiphishing_policies
|
||||
|
||||
def _get_antiphising_rules(self):
|
||||
def _get_antiphishing_rules(self):
|
||||
logger.info("Microsoft365 - Getting Defender antiphishing rules...")
|
||||
antiphishing_rules = {}
|
||||
try:
|
||||
@@ -121,6 +137,10 @@ class Defender(M365Service):
|
||||
if rule:
|
||||
antiphishing_rules[rule.get("Name", "")] = AntiphishingRule(
|
||||
state=rule.get("State", ""),
|
||||
priority=rule.get("Priority", 0),
|
||||
users=rule.get("SentTo", None),
|
||||
groups=rule.get("SentToMemberOf", None),
|
||||
domains=rule.get("RecipientDomainIs", None),
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
@@ -176,6 +196,7 @@ class Defender(M365Service):
|
||||
for policy in outbound_spam_policy:
|
||||
if policy:
|
||||
outbound_spam_policies[policy.get("Name", "")] = OutboundSpamPolicy(
|
||||
name=policy.get("Name", ""),
|
||||
notify_sender_blocked=policy.get("NotifyOutboundSpam", True),
|
||||
notify_limit_exceeded=policy.get(
|
||||
"BccSuspiciousOutboundMail", True
|
||||
@@ -189,6 +210,14 @@ class Defender(M365Service):
|
||||
auto_forwarding_mode=policy.get("AutoForwardingMode", True),
|
||||
default=policy.get("IsDefault", False),
|
||||
)
|
||||
|
||||
outbound_spam_policies = dict(
|
||||
sorted(
|
||||
outbound_spam_policies.items(),
|
||||
key=lambda item: item[1].default,
|
||||
reverse=True,
|
||||
)
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
@@ -206,6 +235,10 @@ class Defender(M365Service):
|
||||
if rule:
|
||||
outbound_spam_rules[rule.get("Name", "")] = OutboundSpamRule(
|
||||
state=rule.get("State", "Disabled"),
|
||||
priority=rule.get("Priority", 0),
|
||||
users=rule.get("From", None),
|
||||
groups=rule.get("FromMemberOf", None),
|
||||
domains=rule.get("SenderDomainIs", None),
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
@@ -230,14 +263,38 @@ class Defender(M365Service):
|
||||
allowed_sender_domains=policy.get(
|
||||
"AllowedSenderDomains", []
|
||||
),
|
||||
default=policy.get("IsDefault", False),
|
||||
)
|
||||
)
|
||||
inbound_spam_policies.sort(key=lambda x: x.default, reverse=True)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return inbound_spam_policies
|
||||
|
||||
def _get_inbound_spam_filter_rule(self):
|
||||
logger.info("Microsoft365 - Getting Defender inbound spam filter rule...")
|
||||
inbound_spam_rules = {}
|
||||
try:
|
||||
inbound_spam_rule = self.powershell.get_inbound_spam_filter_rule()
|
||||
if isinstance(inbound_spam_rule, dict):
|
||||
inbound_spam_rule = [inbound_spam_rule]
|
||||
for rule in inbound_spam_rule:
|
||||
if rule:
|
||||
inbound_spam_rules[rule.get("Name", "")] = InboundSpamRule(
|
||||
state=rule.get("State", "Disabled"),
|
||||
priority=rule.get("Priority", 0),
|
||||
users=rule.get("SentTo", None),
|
||||
groups=rule.get("SentToMemberOf", None),
|
||||
domains=rule.get("RecipientDomainIs", None),
|
||||
)
|
||||
except Exception as error:
|
||||
logger.error(
|
||||
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
|
||||
)
|
||||
return inbound_spam_rules
|
||||
|
||||
def _get_report_submission_policy(self):
|
||||
logger.info("Microsoft365 - Getting Defender report submission policy...")
|
||||
report_submission_policy = None
|
||||
@@ -288,9 +345,14 @@ class MalwarePolicy(BaseModel):
|
||||
|
||||
class MalwareRule(BaseModel):
|
||||
state: str
|
||||
priority: int
|
||||
users: Optional[list[str]]
|
||||
groups: Optional[list[str]]
|
||||
domains: Optional[list[str]]
|
||||
|
||||
|
||||
class AntiphishingPolicy(BaseModel):
|
||||
name: str
|
||||
spoof_intelligence: bool
|
||||
spoof_intelligence_action: str
|
||||
dmarc_reject_action: str
|
||||
@@ -304,6 +366,10 @@ class AntiphishingPolicy(BaseModel):
|
||||
|
||||
class AntiphishingRule(BaseModel):
|
||||
state: str
|
||||
priority: int
|
||||
users: Optional[list[str]]
|
||||
groups: Optional[list[str]]
|
||||
domains: Optional[list[str]]
|
||||
|
||||
|
||||
class ConnectionFilterPolicy(BaseModel):
|
||||
@@ -318,6 +384,7 @@ class DkimConfig(BaseModel):
|
||||
|
||||
|
||||
class OutboundSpamPolicy(BaseModel):
|
||||
name: str
|
||||
notify_sender_blocked: bool
|
||||
notify_limit_exceeded: bool
|
||||
notify_limit_exceeded_addresses: List[str]
|
||||
@@ -328,11 +395,24 @@ class OutboundSpamPolicy(BaseModel):
|
||||
|
||||
class OutboundSpamRule(BaseModel):
|
||||
state: str
|
||||
priority: int
|
||||
users: Optional[list[str]]
|
||||
groups: Optional[list[str]]
|
||||
domains: Optional[list[str]]
|
||||
|
||||
|
||||
class DefenderInboundSpamPolicy(BaseModel):
|
||||
identity: str
|
||||
allowed_sender_domains: list[str] = []
|
||||
default: bool
|
||||
|
||||
|
||||
class InboundSpamRule(BaseModel):
|
||||
state: str
|
||||
priority: int
|
||||
users: Optional[list[str]]
|
||||
groups: Optional[list[str]]
|
||||
domains: Optional[list[str]]
|
||||
|
||||
|
||||
class ReportSubmissionPolicy(BaseModel):
|
||||
|
||||
+340
-137
@@ -4,7 +4,69 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_defender_antiphishing_policy_configured:
|
||||
def test_properly_configured_custom_policy(self):
|
||||
def test_case_1_default_policy_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import (
|
||||
defender_antiphishing_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
AntiphishingPolicy,
|
||||
)
|
||||
|
||||
defender_client.antiphishing_policies = {
|
||||
"Default": AntiphishingPolicy(
|
||||
name="Default",
|
||||
spoof_intelligence=True,
|
||||
spoof_intelligence_action="Quarantine",
|
||||
dmarc_reject_action="Quarantine",
|
||||
dmarc_quarantine_action="Quarantine",
|
||||
safety_tips=True,
|
||||
unauthenticated_sender_action=True,
|
||||
show_tag=True,
|
||||
honor_dmarc_policy=True,
|
||||
default=True,
|
||||
)
|
||||
}
|
||||
defender_client.antiphishing_rules = {}
|
||||
|
||||
check = defender_antiphishing_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the only policy and it's properly configured in the default Defender Anti-Phishing Policy."
|
||||
)
|
||||
assert (
|
||||
result[0].resource_name
|
||||
== defender_client.antiphishing_policies["Default"].name
|
||||
)
|
||||
assert (
|
||||
result[0].resource_id
|
||||
== defender_client.antiphishing_policies["Default"].name
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.antiphishing_policies["Default"].dict()
|
||||
)
|
||||
|
||||
def test_case_2_all_policies_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -31,7 +93,20 @@ class Test_defender_antiphishing_policy_configured:
|
||||
)
|
||||
|
||||
defender_client.antiphishing_policies = {
|
||||
"Default": AntiphishingPolicy(
|
||||
name="Default",
|
||||
spoof_intelligence=True,
|
||||
spoof_intelligence_action="Quarantine",
|
||||
dmarc_reject_action="Quarantine",
|
||||
dmarc_quarantine_action="Quarantine",
|
||||
safety_tips=True,
|
||||
unauthenticated_sender_action=True,
|
||||
show_tag=True,
|
||||
honor_dmarc_policy=True,
|
||||
default=True,
|
||||
),
|
||||
"Policy1": AntiphishingPolicy(
|
||||
name="Policy1",
|
||||
spoof_intelligence=True,
|
||||
spoof_intelligence_action="Quarantine",
|
||||
dmarc_reject_action="Quarantine",
|
||||
@@ -41,29 +116,59 @@ class Test_defender_antiphishing_policy_configured:
|
||||
show_tag=True,
|
||||
honor_dmarc_policy=True,
|
||||
default=False,
|
||||
)
|
||||
),
|
||||
}
|
||||
defender_client.antiphising_rules = {
|
||||
"Policy1": AntiphishingRule(state="Enabled")
|
||||
defender_client.antiphishing_rules = {
|
||||
"Policy1": AntiphishingRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antiphishing_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Anti-phishing policy Policy1 is properly configured and enabled."
|
||||
== "Default is properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another bad-configured Custom Policy."
|
||||
)
|
||||
assert (
|
||||
result[0].resource_name
|
||||
== defender_client.antiphishing_policies["Default"].name
|
||||
)
|
||||
assert (
|
||||
result[0].resource_id
|
||||
== defender_client.antiphishing_policies["Default"].name
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.antiphishing_policies["Default"].dict()
|
||||
)
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== f"Custom Anti-phishing policy {defender_client.antiphishing_policies['Policy1'].name} is properly configured and includes users: {', '.join(defender_client.antiphishing_rules['Policy1'].users)}; groups: {', '.join(defender_client.antiphishing_rules['Policy1'].groups)}; domains: {', '.join(defender_client.antiphishing_rules['Policy1'].domains)}, "
|
||||
f"with priority {defender_client.antiphishing_rules['Policy1'].priority} (0 is the highest). "
|
||||
"Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
assert (
|
||||
result[1].resource_name
|
||||
== defender_client.antiphishing_policies["Policy1"].name
|
||||
)
|
||||
assert (
|
||||
result[1].resource_id
|
||||
== defender_client.antiphishing_policies["Policy1"].name
|
||||
)
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.antiphishing_policies["Policy1"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Anti-Phishing Policy"
|
||||
assert result[0].resource_id == "Policy1"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_not_properly_configured_policy(self):
|
||||
def test_case_3_default_ok_others_not(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -89,66 +194,9 @@ class Test_defender_antiphishing_policy_configured:
|
||||
AntiphishingRule,
|
||||
)
|
||||
|
||||
defender_client.antiphishing_policies = {
|
||||
"Policy2": AntiphishingPolicy(
|
||||
spoof_intelligence=False,
|
||||
spoof_intelligence_action="None",
|
||||
dmarc_reject_action="None",
|
||||
dmarc_quarantine_action="None",
|
||||
safety_tips=False,
|
||||
unauthenticated_sender_action=False,
|
||||
show_tag=False,
|
||||
honor_dmarc_policy=False,
|
||||
default=False,
|
||||
)
|
||||
}
|
||||
defender_client.antiphising_rules = {
|
||||
"Policy2": AntiphishingRule(state="Enabled")
|
||||
}
|
||||
|
||||
check = defender_antiphishing_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Anti-phishing policy Policy2 is not properly configured."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.antiphishing_policies["Policy2"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Anti-Phishing Policy"
|
||||
assert result[0].resource_id == "Policy2"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_properly_configured_default_policy(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import (
|
||||
defender_antiphishing_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
AntiphishingPolicy,
|
||||
)
|
||||
|
||||
defender_client.antiphishing_policies = {
|
||||
"Default": AntiphishingPolicy(
|
||||
name="Default",
|
||||
spoof_intelligence=True,
|
||||
spoof_intelligence_action="Quarantine",
|
||||
dmarc_reject_action="Quarantine",
|
||||
@@ -158,27 +206,149 @@ class Test_defender_antiphishing_policy_configured:
|
||||
show_tag=True,
|
||||
honor_dmarc_policy=True,
|
||||
default=True,
|
||||
),
|
||||
"Policy1": AntiphishingPolicy(
|
||||
name="Policy1",
|
||||
spoof_intelligence=False,
|
||||
spoof_intelligence_action="None",
|
||||
dmarc_reject_action="None",
|
||||
dmarc_quarantine_action="None",
|
||||
safety_tips=False,
|
||||
unauthenticated_sender_action=False,
|
||||
show_tag=False,
|
||||
honor_dmarc_policy=False,
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
defender_client.antiphishing_rules = {
|
||||
"Policy1": AntiphishingRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
defender_client.antiphising_rules = {}
|
||||
|
||||
check = defender_antiphishing_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Anti-phishing policy Default is properly configured and enabled."
|
||||
== "Default is properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another bad-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.antiphishing_policies["Default"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Anti-Phishing Policy"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_default_policy_not_properly_configured(self):
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Anti-phishing policy Policy1 is not properly configured and includes users: test@example.com; groups: example_group; domains: example.com, "
|
||||
"with priority 1 (0 is the highest). However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.antiphishing_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_case_4_default_not_ok_potential_false_positive(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import (
|
||||
defender_antiphishing_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
AntiphishingPolicy,
|
||||
AntiphishingRule,
|
||||
)
|
||||
|
||||
defender_client.antiphishing_policies = {
|
||||
"Default": AntiphishingPolicy(
|
||||
name="Default",
|
||||
spoof_intelligence=False,
|
||||
spoof_intelligence_action="None",
|
||||
dmarc_reject_action="None",
|
||||
dmarc_quarantine_action="None",
|
||||
safety_tips=False,
|
||||
unauthenticated_sender_action=False,
|
||||
show_tag=False,
|
||||
honor_dmarc_policy=False,
|
||||
default=True,
|
||||
),
|
||||
"Policy1": AntiphishingPolicy(
|
||||
name="Policy1",
|
||||
spoof_intelligence=True,
|
||||
spoof_intelligence_action="Quarantine",
|
||||
dmarc_reject_action="Quarantine",
|
||||
dmarc_quarantine_action="Quarantine",
|
||||
safety_tips=True,
|
||||
unauthenticated_sender_action=True,
|
||||
show_tag=True,
|
||||
honor_dmarc_policy=True,
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
defender_client.antiphishing_rules = {
|
||||
"Policy1": AntiphishingRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antiphishing_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is not properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.antiphishing_policies["Default"].dict()
|
||||
)
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Anti-phishing policy Policy1 is properly configured and includes users: test@example.com; groups: example_group; domains: example.com, "
|
||||
f"with priority {defender_client.antiphishing_rules['Policy1'].priority} (0 is the highest). "
|
||||
"However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.antiphishing_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_case_5_default_policy_not_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -205,6 +375,7 @@ class Test_defender_antiphishing_policy_configured:
|
||||
|
||||
defender_client.antiphishing_policies = {
|
||||
"Default": AntiphishingPolicy(
|
||||
name="Default",
|
||||
spoof_intelligence=False,
|
||||
spoof_intelligence_action="None",
|
||||
dmarc_reject_action="None",
|
||||
@@ -216,7 +387,7 @@ class Test_defender_antiphishing_policy_configured:
|
||||
default=True,
|
||||
)
|
||||
}
|
||||
defender_client.antiphising_rules = {}
|
||||
defender_client.antiphishing_rules = {}
|
||||
|
||||
check = defender_antiphishing_policy_configured()
|
||||
result = check.execute()
|
||||
@@ -224,15 +395,103 @@ class Test_defender_antiphishing_policy_configured:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Anti-phishing policy Default is not properly configured."
|
||||
== "Default is the only policy and it's not properly configured in the default Defender Anti-Phishing Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.antiphishing_policies["Default"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Anti-Phishing Policy"
|
||||
|
||||
def test_case_6_both_policies_not_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import (
|
||||
defender_antiphishing_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
AntiphishingPolicy,
|
||||
AntiphishingRule,
|
||||
)
|
||||
|
||||
defender_client.antiphishing_policies = {
|
||||
"Default": AntiphishingPolicy(
|
||||
name="Default",
|
||||
spoof_intelligence=False,
|
||||
spoof_intelligence_action="None",
|
||||
dmarc_reject_action="None",
|
||||
dmarc_quarantine_action="None",
|
||||
safety_tips=False,
|
||||
unauthenticated_sender_action=False,
|
||||
show_tag=False,
|
||||
honor_dmarc_policy=False,
|
||||
default=True,
|
||||
),
|
||||
"Policy1": AntiphishingPolicy(
|
||||
name="Policy1",
|
||||
spoof_intelligence=False,
|
||||
spoof_intelligence_action="None",
|
||||
dmarc_reject_action="None",
|
||||
dmarc_quarantine_action="None",
|
||||
safety_tips=False,
|
||||
unauthenticated_sender_action=False,
|
||||
show_tag=False,
|
||||
honor_dmarc_policy=False,
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
defender_client.antiphishing_rules = {
|
||||
"Policy1": AntiphishingRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=[],
|
||||
groups=[],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antiphishing_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is not properly configured in the default Defender Anti-Phishing Policy, but could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].location == "global"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.antiphishing_policies["Default"].dict()
|
||||
)
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Anti-phishing policy Policy1 is not properly configured and includes domains: example.com, "
|
||||
"with priority 1 (0 is the highest). Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.antiphishing_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_no_antiphishing_policies(self):
|
||||
defender_client = mock.MagicMock()
|
||||
@@ -257,64 +516,8 @@ class Test_defender_antiphishing_policy_configured:
|
||||
)
|
||||
|
||||
defender_client.antiphishing_policies = {}
|
||||
defender_client.antiphising_rules = {}
|
||||
defender_client.antiphishing_rules = {}
|
||||
|
||||
check = defender_antiphishing_policy_configured()
|
||||
result = check.execute()
|
||||
assert result == []
|
||||
|
||||
def test_custom_policy_without_rule(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antiphishing_policy_configured.defender_antiphishing_policy_configured import (
|
||||
defender_antiphishing_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
AntiphishingPolicy,
|
||||
)
|
||||
|
||||
defender_client.antiphishing_policies = {
|
||||
"PolicyX": AntiphishingPolicy(
|
||||
spoof_intelligence=True,
|
||||
spoof_intelligence_action="Quarantine",
|
||||
dmarc_reject_action="Quarantine",
|
||||
dmarc_quarantine_action="Quarantine",
|
||||
safety_tips=True,
|
||||
unauthenticated_sender_action=True,
|
||||
show_tag=True,
|
||||
honor_dmarc_policy=True,
|
||||
default=False,
|
||||
)
|
||||
}
|
||||
defender_client.antiphising_rules = {}
|
||||
|
||||
check = defender_antiphishing_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Anti-phishing policy PolicyX is not properly configured."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.antiphishing_policies["PolicyX"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Anti-Phishing Policy"
|
||||
assert result[0].resource_id == "PolicyX"
|
||||
assert result[0].location == "global"
|
||||
assert len(result) == 0
|
||||
|
||||
+360
-133
@@ -4,119 +4,7 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_defender_antispam_outbound_policy_configured:
|
||||
def test_properly_configured_custom_policy(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import (
|
||||
defender_antispam_outbound_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
default=False,
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(state="Enabled")
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy Policy1 is properly configured and enabled."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "Policy1"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_not_properly_configured_policy(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import (
|
||||
defender_antispam_outbound_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Policy2": OutboundSpamPolicy(
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
default=False,
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy2": OutboundSpamRule(state="Enabled")
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy Policy2 is not properly configured."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Policy2"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "Policy2"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_properly_configured_default_policy(self):
|
||||
def test_case_1_default_policy_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -143,12 +31,13 @@ class Test_defender_antispam_outbound_policy_configured:
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
notify_sender_blocked=True,
|
||||
name="Default",
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
default=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
auto_forwarding_mode=False,
|
||||
default=True,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
@@ -159,17 +48,271 @@ class Test_defender_antispam_outbound_policy_configured:
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy Default is properly configured and enabled."
|
||||
== "Default is the only policy and it's properly configured in the default Defender Outbound Spam Policy."
|
||||
)
|
||||
assert (
|
||||
result[0].resource_name
|
||||
== defender_client.outbound_spam_policies["Default"].name
|
||||
)
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_policy_without_rule(self):
|
||||
def test_case_2_all_policies_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import (
|
||||
defender_antispam_outbound_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
notify_limit_exceeded=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
auto_forwarding_mode=False,
|
||||
default=True,
|
||||
),
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
name="Policy1",
|
||||
notify_limit_exceeded=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
auto_forwarding_mode=False,
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is properly configured in the default Defender Outbound Spam Policy, but could be overridden by another bad-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Outbound Spam policy Policy1 is properly configured and includes users: test@example.com; groups: group1; domains: example.com, "
|
||||
"with priority 1 (0 is the highest). Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_case_3_default_ok_others_not(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import (
|
||||
defender_antispam_outbound_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
notify_limit_exceeded=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
auto_forwarding_mode=False,
|
||||
default=True,
|
||||
),
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
name="Policy1",
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
auto_forwarding_mode=False,
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is properly configured in the default Defender Outbound Spam Policy, but could be overridden by another bad-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Outbound Spam policy Policy1 is not properly configured and includes users: test@example.com; groups: group1; domains: example.com, "
|
||||
"with priority 1 (0 is the highest). However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_case_4_default_not_ok_custom_good(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import (
|
||||
defender_antispam_outbound_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
auto_forwarding_mode=False,
|
||||
default=True,
|
||||
),
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
name="Policy1",
|
||||
notify_limit_exceeded=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
auto_forwarding_mode=False,
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=0,
|
||||
users=["user1@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is not properly configured in the default Defender Outbound Spam Policy, but could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Outbound Spam policy Policy1 is properly configured and includes users: user1@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 0 (0 is the highest). However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_case_5_only_default_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -195,13 +338,14 @@ class Test_defender_antispam_outbound_policy_configured:
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"PolicyX": OutboundSpamPolicy(
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["admin@org.com"],
|
||||
notify_sender_blocked_addresses=["admin@org.com"],
|
||||
default=False,
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
auto_forwarding_mode=False,
|
||||
default=True,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
@@ -212,15 +356,98 @@ class Test_defender_antispam_outbound_policy_configured:
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy PolicyX is not properly configured."
|
||||
== "Default is the only policy and it's not properly configured in the default Defender Outbound Spam Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["PolicyX"].dict()
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
def test_case_6_default_and_custom_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_configured.defender_antispam_outbound_policy_configured import (
|
||||
defender_antispam_outbound_policy_configured,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
auto_forwarding_mode=False,
|
||||
default=True,
|
||||
),
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
name="Policy1",
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
auto_forwarding_mode=False,
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=5,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_configured()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is not properly configured in the default Defender Outbound Spam Policy, but could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Outbound Spam policy Policy1 is not properly configured and includes users: user@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 5 (0 is the highest). Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "PolicyX"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_no_outbound_spam_policies(self):
|
||||
defender_client = mock.MagicMock()
|
||||
|
||||
+450
-218
@@ -4,6 +4,456 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_defender_antispam_outbound_policy_forwarding_disabled:
|
||||
def test_case_1_default_policy_forwarding_disabled(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
auto_forwarding_mode=False,
|
||||
notify_limit_exceeded=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
default=True,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the only policy and mail forwarding is disabled."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
def test_case_2_all_policies_forwarding_disabled(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
auto_forwarding_mode=False,
|
||||
notify_limit_exceeded=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
default=True,
|
||||
),
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
name="Policy1",
|
||||
auto_forwarding_mode=False,
|
||||
notify_limit_exceeded=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and mail forwarding is disabled, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Outbound Spam policy Policy1 disables mail forwarding and includes users: test@example.com; groups: group1; domains: example.com, "
|
||||
"with priority 1 (0 is the highest). Also, the default policy disables mail forwarding, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_case_3_default_ok_custom_not(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
auto_forwarding_mode=False,
|
||||
notify_limit_exceeded=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
default=True,
|
||||
),
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
name="Policy1",
|
||||
auto_forwarding_mode=True,
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and mail forwarding is disabled, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Outbound Spam policy Policy1 allows mail forwarding and includes users: test@example.com; groups: group1; domains: example.com, "
|
||||
"with priority 1 (0 is the highest). However, the default policy disables mail forwarding, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_case_4_default_not_ok_custom_good(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
auto_forwarding_mode=True,
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
default=True,
|
||||
),
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
name="Policy1",
|
||||
auto_forwarding_mode=False,
|
||||
notify_limit_exceeded=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded_addresses=["admin@example.com"],
|
||||
notify_sender_blocked_addresses=["admin@example.com"],
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=0,
|
||||
users=["user1@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and mail forwarding is allowed, but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Outbound Spam policy Policy1 disables mail forwarding and includes users: user1@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 0 (0 is the highest). However, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_case_5_only_default_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
auto_forwarding_mode=True,
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
default=True,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the only policy and mail forwarding is allowed."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
def test_case_6_default_and_custom_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
name="Default",
|
||||
auto_forwarding_mode=True,
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
default=True,
|
||||
),
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
name="Policy1",
|
||||
auto_forwarding_mode=True,
|
||||
notify_limit_exceeded=False,
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
notify_sender_blocked_addresses=[],
|
||||
default=False,
|
||||
),
|
||||
}
|
||||
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and mail forwarding is allowed, but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Outbound Spam policy Policy1 allows mail forwarding and includes users: user@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 1 (0 is the highest). Also, the default policy allows mail forwarding, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert (
|
||||
result[1].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
|
||||
def test_no_outbound_spam_policies(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
@@ -32,221 +482,3 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled:
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
def test_forwarding_disabled_custom_policy(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
default=False,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy1": OutboundSpamRule(state="Enabled")
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy Policy1 does not allow mail forwarding."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Policy1"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "Policy1"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_forwarding_enabled_policy(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
OutboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Policy2": OutboundSpamPolicy(
|
||||
default=False,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
auto_forwarding_mode=True,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {
|
||||
"Policy2": OutboundSpamRule(state="Enabled")
|
||||
}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy Policy2 does allow mail forwarding."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Policy2"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "Policy2"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_forwarding_disabled_default_policy(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"Default": OutboundSpamPolicy(
|
||||
default=True,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy Default does not allow mail forwarding."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["Default"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_policy_without_rule(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_outbound_policy_forwarding_disabled.defender_antispam_outbound_policy_forwarding_disabled import (
|
||||
defender_antispam_outbound_policy_forwarding_disabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
OutboundSpamPolicy,
|
||||
)
|
||||
|
||||
defender_client.outbound_spam_policies = {
|
||||
"PolicyX": OutboundSpamPolicy(
|
||||
default=False,
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["test@correo.com"],
|
||||
notify_sender_blocked_addresses=["test@correo.com"],
|
||||
auto_forwarding_mode=False,
|
||||
)
|
||||
}
|
||||
defender_client.outbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_outbound_policy_forwarding_disabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Outbound Spam Policy PolicyX does allow mail forwarding."
|
||||
)
|
||||
assert (
|
||||
result[0].resource
|
||||
== defender_client.outbound_spam_policies["PolicyX"].dict()
|
||||
)
|
||||
assert result[0].resource_name == "Defender Outbound Spam Policy"
|
||||
assert result[0].resource_id == "PolicyX"
|
||||
assert result[0].location == "global"
|
||||
|
||||
+302
-16
@@ -4,7 +4,7 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_defender_antispam_policy_inbound_no_allowed_domains:
|
||||
def test_policy_without_allowed_domains(self):
|
||||
def test_case_1_default_policy_no_allowed_domains(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -31,26 +31,240 @@ class Test_defender_antispam_policy_inbound_no_allowed_domains:
|
||||
|
||||
defender_client.inbound_spam_policies = [
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Policy1",
|
||||
identity="Default",
|
||||
default=True,
|
||||
allowed_sender_domains=[],
|
||||
)
|
||||
]
|
||||
defender_client.inbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_policy_inbound_no_allowed_domains()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Inbound anti-spam policy Policy1 does not contain allowed domains."
|
||||
== "Default is the only policy and it does not contain allowed domains."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.inbound_spam_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Inbound Spam Policy"
|
||||
assert result[0].resource_id == "Policy1"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_policy_with_allowed_domains(self):
|
||||
def test_case_2_all_policies_no_allowed_domains(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import (
|
||||
defender_antispam_policy_inbound_no_allowed_domains,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
DefenderInboundSpamPolicy,
|
||||
InboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.inbound_spam_policies = [
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Default",
|
||||
default=True,
|
||||
allowed_sender_domains=[],
|
||||
),
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Policy1",
|
||||
default=False,
|
||||
allowed_sender_domains=[],
|
||||
),
|
||||
]
|
||||
defender_client.inbound_spam_rules = {
|
||||
"Policy1": InboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["user1@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_policy_inbound_no_allowed_domains()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and it does not contain allowed domains, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.inbound_spam_policies[0].dict()
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Inbound Spam policy Policy1 does not contain allowed domains and includes users: user1@example.com; groups: group1; domains: example.com, "
|
||||
"with priority 1 (0 is the highest). Also, the default policy does not contain allowed domains, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.inbound_spam_policies[1].dict()
|
||||
|
||||
def test_case_3_default_ok_custom_with_allowed_domains(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import (
|
||||
defender_antispam_policy_inbound_no_allowed_domains,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
DefenderInboundSpamPolicy,
|
||||
InboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.inbound_spam_policies = [
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Default",
|
||||
default=True,
|
||||
allowed_sender_domains=[],
|
||||
),
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Policy1",
|
||||
default=False,
|
||||
allowed_sender_domains=["spam.com"],
|
||||
),
|
||||
]
|
||||
defender_client.inbound_spam_rules = {
|
||||
"Policy1": InboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=2,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_policy_inbound_no_allowed_domains()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and it does not contain allowed domains, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.inbound_spam_policies[0].dict()
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Inbound Spam policy Policy1 contains allowed domains and includes users: user@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 2 (0 is the highest). However, the default policy does not contain allowed domains, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.inbound_spam_policies[1].dict()
|
||||
|
||||
def test_case_4_default_with_allowed_domains_custom_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import (
|
||||
defender_antispam_policy_inbound_no_allowed_domains,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
DefenderInboundSpamPolicy,
|
||||
InboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.inbound_spam_policies = [
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Default",
|
||||
default=True,
|
||||
allowed_sender_domains=["example.org"],
|
||||
),
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Policy1",
|
||||
default=False,
|
||||
allowed_sender_domains=[],
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.inbound_spam_rules = {
|
||||
"Policy1": InboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=0,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_policy_inbound_no_allowed_domains()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and it contains allowed domains: example.org, but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.inbound_spam_policies[0].dict()
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Inbound Spam policy Policy1 does not contain allowed domains and includes users: user@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 0 (0 is the highest). However, the default policy contains allowed domains, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.inbound_spam_policies[1].dict()
|
||||
|
||||
def test_case_5_default_with_allowed_domains(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -77,24 +291,96 @@ class Test_defender_antispam_policy_inbound_no_allowed_domains:
|
||||
|
||||
defender_client.inbound_spam_policies = [
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Policy2",
|
||||
allowed_sender_domains=["bad-domain.com"],
|
||||
identity="Default",
|
||||
default=True,
|
||||
allowed_sender_domains=["example.com"],
|
||||
)
|
||||
]
|
||||
defender_client.inbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_policy_inbound_no_allowed_domains()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Inbound anti-spam policy Policy2 contains allowed domains: ['bad-domain.com']."
|
||||
== "Default is the only policy and it contains allowed domains: example.com."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.inbound_spam_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Inbound Spam Policy"
|
||||
assert result[0].resource_id == "Policy2"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_case_6_both_default_and_custom_with_allowed_domains(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_antispam_policy_inbound_no_allowed_domains.defender_antispam_policy_inbound_no_allowed_domains import (
|
||||
defender_antispam_policy_inbound_no_allowed_domains,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
DefenderInboundSpamPolicy,
|
||||
InboundSpamRule,
|
||||
)
|
||||
|
||||
defender_client.inbound_spam_policies = [
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Default",
|
||||
default=True,
|
||||
allowed_sender_domains=["example.com"],
|
||||
),
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Policy1",
|
||||
default=False,
|
||||
allowed_sender_domains=["spam.com"],
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.inbound_spam_rules = {
|
||||
"Policy1": InboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=5,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_antispam_policy_inbound_no_allowed_domains()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and it contains allowed domains: example.com, but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.inbound_spam_policies[0].dict()
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Inbound Spam policy Policy1 contains allowed domains and includes users: user@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 5 (0 is the highest). Also, the default policy contains allowed domains, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.inbound_spam_policies[1].dict()
|
||||
|
||||
def test_no_inbound_spam_policies(self):
|
||||
defender_client = mock.MagicMock()
|
||||
@@ -119,8 +405,8 @@ class Test_defender_antispam_policy_inbound_no_allowed_domains:
|
||||
)
|
||||
|
||||
defender_client.inbound_spam_policies = []
|
||||
defender_client.inbound_spam_rules = {}
|
||||
|
||||
check = defender_antispam_policy_inbound_no_allowed_domains()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 0
|
||||
|
||||
+336
-34
@@ -4,7 +4,7 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_defender_malware_policy_common_attachments_filter_enabled:
|
||||
def test_enable_file_filter_disabled(self):
|
||||
def test_case_1_only_default_policy_enabled(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -31,30 +31,29 @@ class Test_defender_malware_policy_common_attachments_filter_enabled:
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
enable_file_filter=False,
|
||||
identity="Policy1",
|
||||
enable_internal_sender_admin_notifications=False,
|
||||
internal_sender_admin_address="",
|
||||
file_types=[],
|
||||
identity="Default",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe", "js"],
|
||||
is_default=True,
|
||||
),
|
||||
)
|
||||
]
|
||||
defender_client.malware_rules = {}
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is not enabled in anti-malware policy Policy1."
|
||||
== "Default is the only policy and Common Attachment Types Filter is enabled."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_enable_file_filter_enabled(self):
|
||||
def test_case_2_all_policies_enabled(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -77,34 +76,345 @@ class Test_defender_malware_policy_common_attachments_filter_enabled:
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=True,
|
||||
identity="Policy1",
|
||||
enable_internal_sender_admin_notifications=False,
|
||||
internal_sender_admin_address="",
|
||||
file_types=[],
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe", "js"],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Policy1",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe"],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.malware_rules = {
|
||||
"Policy1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["user1@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is enabled in anti-malware policy Policy1."
|
||||
== "Default is the default policy and Common Attachment Types Filter is enabled, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_no_policy(self):
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Policy1 enables Common Attachment Types Filter and includes users: user1@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 1 (0 is the highest). Also, the default policy enables the filter, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_case_3_default_ok_custom_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import (
|
||||
defender_malware_policy_common_attachments_filter_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe"],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Policy1",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["js"],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.malware_rules = {
|
||||
"Policy1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=2,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and Common Attachment Types Filter is enabled, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Policy1 does not enable Common Attachment Types Filter and includes users: user@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 2 (0 is the highest). However, the default policy enables the filter, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_case_4_default_not_ok_custom_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import (
|
||||
defender_malware_policy_common_attachments_filter_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Policy1",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe"],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.malware_rules = {
|
||||
"Policy1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=0,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and Common Attachment Types Filter is not enabled, but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Policy1 enables Common Attachment Types Filter and includes users: user@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 0 (0 is the highest). However, the default policy does not enable the filter, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_case_5_only_default_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import (
|
||||
defender_malware_policy_common_attachments_filter_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
)
|
||||
]
|
||||
defender_client.malware_rules = {}
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the only policy and Common Attachment Types Filter is not enabled."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
def test_case_6_default_and_custom_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_common_attachments_filter_enabled.defender_malware_policy_common_attachments_filter_enabled import (
|
||||
defender_malware_policy_common_attachments_filter_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Policy1",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe"],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.malware_rules = {
|
||||
"Policy1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=5,
|
||||
users=["user1@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and Common Attachment Types Filter is not enabled, but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Policy1 does not enable Common Attachment Types Filter and includes users: user1@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 5 (0 is the highest). Also, the default policy does not enable the filter, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_no_malware_policies(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -127,16 +437,8 @@ class Test_defender_malware_policy_common_attachments_filter_enabled:
|
||||
)
|
||||
|
||||
defender_client.malware_policies = []
|
||||
defender_client.malware_rules = {}
|
||||
|
||||
check = defender_malware_policy_common_attachments_filter_enabled()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is not enabled."
|
||||
)
|
||||
assert result[0].resource == {}
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
assert len(result) == 0
|
||||
|
||||
+404
-209
@@ -1,53 +1,10 @@
|
||||
from unittest import mock
|
||||
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_defender_malware_policy_comprehensive_attachments_filter_applied:
|
||||
def test_no_policy(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
defender_client.malware_policies = []
|
||||
defender_client.audit_config = {}
|
||||
defender_client.malware_rules = {}
|
||||
|
||||
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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is not enabled."
|
||||
)
|
||||
assert result[0].resource == {}
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_policy_enabled_all_extensions_blocked(self):
|
||||
def test_case_1_default_policy_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -68,192 +25,430 @@ class Test_defender_malware_policy_comprehensive_attachments_filter_applied:
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
|
||||
valid_extensions = ["exe", "bat", "js"]
|
||||
defender_client.audit_config = {
|
||||
"recommended_blocked_file_types": valid_extensions
|
||||
}
|
||||
defender_client.malware_rules = {"PolicyGood": MalwareRule(state="Enabled")}
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
enable_file_filter=True,
|
||||
identity="PolicyGood",
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=valid_extensions,
|
||||
is_default=True,
|
||||
)
|
||||
]
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is enabled in anti-malware policy PolicyGood, the policy is enabled and the filter is applied to the recommended file types."
|
||||
)
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_policy_enabled_missing_extensions(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
)
|
||||
|
||||
defender_client.audit_config = {
|
||||
"recommended_blocked_file_types": ["exe", "bat", "js"]
|
||||
}
|
||||
defender_client.malware_rules = {
|
||||
"PolicyPartial": MalwareRule(state="Enabled")
|
||||
}
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=True,
|
||||
identity="PolicyPartial",
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe"],
|
||||
file_types=["exe", "bat", "js"],
|
||||
is_default=True,
|
||||
)
|
||||
]
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is enabled in anti-malware policy PolicyPartial, but the following recommended file types are missing: bat, js."
|
||||
)
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_policy_enabled_but_rule_disabled(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
|
||||
valid_extensions = ["exe"]
|
||||
defender_client.audit_config = {
|
||||
"recommended_blocked_file_types": valid_extensions
|
||||
}
|
||||
defender_client.malware_rules = {
|
||||
"PolicyDisabled": MalwareRule(state="Disabled")
|
||||
}
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
enable_file_filter=True,
|
||||
identity="PolicyDisabled",
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=valid_extensions,
|
||||
is_default=False,
|
||||
)
|
||||
]
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is enabled in anti-malware policy PolicyDisabled, but the policy is disabled."
|
||||
)
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_policy_enabled_but_no_rule_and_not_default(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
|
||||
valid_extensions = ["exe"]
|
||||
defender_client.audit_config = {
|
||||
"recommended_blocked_file_types": valid_extensions
|
||||
}
|
||||
defender_client.malware_rules = {}
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
enable_file_filter=True,
|
||||
identity="PolicyNoRule",
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=valid_extensions,
|
||||
is_default=False,
|
||||
)
|
||||
]
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the only policy and Common Attachment Types Filter is properly configured."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
def test_case_2_all_policies_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.audit_config = {
|
||||
"recommended_blocked_file_types": ["exe", "bat"]
|
||||
}
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe", "bat"],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Custom1",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe", "bat"],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
defender_client.malware_rules = {
|
||||
"Custom1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["user1@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and Common Attachment Types Filter is properly configured, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Custom1 is properly configured and includes users: user1@example.com; groups: group1; domains: example.com, "
|
||||
"with priority 1 (0 is the highest). Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Custom1"
|
||||
assert result[1].resource_id == "Custom1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_case_3_default_ok_custom_not(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.audit_config = {
|
||||
"recommended_blocked_file_types": ["exe", "bat"]
|
||||
}
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe", "bat"],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Custom1",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe"], # missing bat
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
defender_client.malware_rules = {
|
||||
"Custom1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["user1@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and Common Attachment Types Filter is properly configured, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Custom1 is not properly configured and includes users: user1@example.com; groups: group1; domains: example.com, "
|
||||
"with priority 1 (0 is the highest). Missing recommended file types: bat. However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Custom1"
|
||||
assert result[1].resource_id == "Custom1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_case_4_default_not_ok_custom_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.audit_config = {
|
||||
"recommended_blocked_file_types": ["exe", "bat"]
|
||||
}
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Custom1",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe", "bat"],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
defender_client.malware_rules = {
|
||||
"Custom1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=0,
|
||||
users=["user1@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and Common Attachment Types Filter is not properly configured, but it could be overridden by another well-configured Custom Policy. Missing recommended file types: exe, bat."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Custom1 is properly configured and includes users: user1@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 0 (0 is the highest). However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Custom1"
|
||||
assert result[1].resource_id == "Custom1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_case_5_only_default_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
)
|
||||
|
||||
defender_client.audit_config = {
|
||||
"recommended_blocked_file_types": ["exe", "bat"]
|
||||
}
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
)
|
||||
]
|
||||
defender_client.malware_rules = {}
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Common Attachment Types Filter is not properly configured in anti-malware policy PolicyNoRule."
|
||||
== "Default is the only policy and Common Attachment Types Filter is not properly configured. Missing recommended file types: exe, bat."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_case_6_default_and_custom_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.audit_config = {
|
||||
"recommended_blocked_file_types": ["exe", "bat"]
|
||||
}
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Custom1",
|
||||
enable_file_filter=True,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=["exe"], # missing bat
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
defender_client.malware_rules = {
|
||||
"Custom1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=2,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["example.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and Common Attachment Types Filter is not properly configured, but it could be overridden by another well-configured Custom Policy. Missing recommended file types: exe, bat."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Custom1 is not properly configured and includes users: user@example.com; groups: group1; domains: example.com, "
|
||||
"with priority 2 (0 is the highest). Missing recommended file types: bat. Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Custom1"
|
||||
assert result[1].resource_id == "Custom1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_no_malware_policies(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
defender_client.malware_policies = []
|
||||
defender_client.malware_rules = {}
|
||||
defender_client.audit_config = {}
|
||||
|
||||
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.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_comprehensive_attachments_filter_applied.defender_malware_policy_comprehensive_attachments_filter_applied import (
|
||||
defender_malware_policy_comprehensive_attachments_filter_applied,
|
||||
)
|
||||
|
||||
check = defender_malware_policy_comprehensive_attachments_filter_applied()
|
||||
result = check.execute()
|
||||
assert len(result) == 0
|
||||
|
||||
+338
-41
@@ -4,7 +4,7 @@ from tests.providers.m365.m365_fixtures import DOMAIN, set_mocked_m365_provider
|
||||
|
||||
|
||||
class Test_defender_malware_policy_notifications_internal_users_malware_enabled:
|
||||
def test_notifications_disabled(self):
|
||||
def test_case_1_default_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -31,32 +31,322 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled:
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
enable_file_filter=True,
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
)
|
||||
]
|
||||
defender_client.malware_rules = {}
|
||||
|
||||
check = (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled()
|
||||
)
|
||||
result = check.execute()
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the only policy and notifications for internal users sending malware are enabled."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
def test_case_2_default_and_custom_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Policy1",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.malware_rules = {
|
||||
"Policy1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled()
|
||||
)
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and notifications for internal users sending malware are enabled, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Policy1 is properly configured and includes users: user@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 1 (0 is the highest). Also, the default policy is properly configured, so entities not included by this custom policy could still be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_case_3_default_ok_custom_not_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Policy1",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=False,
|
||||
internal_sender_admin_address="",
|
||||
file_types=[],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.malware_rules = {
|
||||
"Policy1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=2,
|
||||
users=["internal@example.com"],
|
||||
groups=["group2"],
|
||||
domains=["example.org"],
|
||||
)
|
||||
}
|
||||
|
||||
check = (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled()
|
||||
)
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and notifications for internal users sending malware are enabled, but it could be overridden by another misconfigured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Policy1 is not properly configured and includes users: internal@example.com; groups: group2; domains: example.org, "
|
||||
"with priority 2 (0 is the highest). However, the default policy is properly configured, so entities not included by this custom policy could be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_case_4_default_not_ok_custom_properly_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=False,
|
||||
internal_sender_admin_address="",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Policy1",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="admin@example.com",
|
||||
file_types=[],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.malware_rules = {
|
||||
"Policy1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=0,
|
||||
users=["user@example.com"],
|
||||
groups=["group1"],
|
||||
domains=["domain.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled()
|
||||
)
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Default is the default policy and notifications for internal users sending malware are not enabled, but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
|
||||
assert result[1].status == "PASS"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Policy1 is properly configured and includes users: user@example.com; groups: group1; domains: domain.com, "
|
||||
"with priority 0 (0 is the highest). However, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_case_5_only_default_not_ok(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_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.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled.defender_client",
|
||||
new=defender_client,
|
||||
),
|
||||
):
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
identity="Default",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=False,
|
||||
internal_sender_admin_address="",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
)
|
||||
]
|
||||
defender_client.malware_rules = {}
|
||||
|
||||
check = (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled()
|
||||
)
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Notifications for internal users sending malware are not enabled."
|
||||
== "Default is the only policy and notifications for internal users sending malware are not enabled."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_notifications_enabled_without_email(self):
|
||||
def test_case_6_default_and_custom_not_configured(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -79,36 +369,64 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled:
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
enable_file_filter=True,
|
||||
identity="Default",
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=False,
|
||||
internal_sender_admin_address="",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
)
|
||||
),
|
||||
MalwarePolicy(
|
||||
identity="Policy1",
|
||||
enable_file_filter=False,
|
||||
enable_internal_sender_admin_notifications=False,
|
||||
internal_sender_admin_address="",
|
||||
file_types=[],
|
||||
is_default=False,
|
||||
),
|
||||
]
|
||||
|
||||
defender_client.malware_rules = {
|
||||
"Policy1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=3,
|
||||
users=["u@example.com"],
|
||||
groups=["g1"],
|
||||
domains=["d.com"],
|
||||
)
|
||||
}
|
||||
|
||||
check = (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled()
|
||||
)
|
||||
result = check.execute()
|
||||
assert len(result) == 2
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Notifications for internal users sending malware are enabled, but no email addresses are configured."
|
||||
== "Default is the default policy and notifications for internal users sending malware are not enabled, but it could be overridden by another well-configured Custom Policy."
|
||||
)
|
||||
assert result[0].resource_name == "Default"
|
||||
assert result[0].resource_id == "Default"
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
|
||||
def test_notifications_enabled_with_email(self):
|
||||
assert result[1].status == "FAIL"
|
||||
assert (
|
||||
result[1].status_extended
|
||||
== "Custom Malware policy Policy1 is not properly configured and includes users: u@example.com; groups: g1; domains: d.com, "
|
||||
"with priority 3 (0 is the highest). Also, the default policy is not properly configured, so entities not included by this custom policy could not be correctly protected."
|
||||
)
|
||||
assert result[1].resource_name == "Policy1"
|
||||
assert result[1].resource_id == "Policy1"
|
||||
assert result[1].resource == defender_client.malware_policies[1].dict()
|
||||
|
||||
def test_no_malware_policies(self):
|
||||
defender_client = mock.MagicMock()
|
||||
defender_client.audited_tenant = "audited_tenant"
|
||||
defender_client.audited_domain = DOMAIN
|
||||
@@ -129,33 +447,12 @@ class Test_defender_malware_policy_notifications_internal_users_malware_enabled:
|
||||
from prowler.providers.m365.services.defender.defender_malware_policy_notifications_internal_users_malware_enabled.defender_malware_policy_notifications_internal_users_malware_enabled import (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled,
|
||||
)
|
||||
from prowler.providers.m365.services.defender.defender_service import (
|
||||
MalwarePolicy,
|
||||
)
|
||||
|
||||
defender_client.malware_policies = [
|
||||
MalwarePolicy(
|
||||
enable_file_filter=True,
|
||||
identity="Default",
|
||||
enable_internal_sender_admin_notifications=True,
|
||||
internal_sender_admin_address="security@example.com",
|
||||
file_types=[],
|
||||
is_default=True,
|
||||
)
|
||||
]
|
||||
defender_client.malware_policies = []
|
||||
defender_client.malware_rules = {}
|
||||
|
||||
check = (
|
||||
defender_malware_policy_notifications_internal_users_malware_enabled()
|
||||
)
|
||||
result = check.execute()
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Notifications for internal users sending malware are enabled."
|
||||
)
|
||||
assert result[0].resource == defender_client.malware_policies[0].dict()
|
||||
assert result[0].resource_name == "Defender Malware Policy"
|
||||
assert result[0].resource_id == "defenderMalwarePolicy"
|
||||
assert result[0].location == "global"
|
||||
assert len(result) == 0
|
||||
|
||||
@@ -9,6 +9,7 @@ from prowler.providers.m365.services.defender.defender_service import (
|
||||
Defender,
|
||||
DefenderInboundSpamPolicy,
|
||||
DkimConfig,
|
||||
InboundSpamRule,
|
||||
MalwarePolicy,
|
||||
MalwareRule,
|
||||
OutboundSpamPolicy,
|
||||
@@ -41,14 +42,27 @@ def mock_defender_get_malware_filter_policy(_):
|
||||
|
||||
def mock_defender_get_malware_filter_rule(_):
|
||||
return {
|
||||
"Policy1": MalwareRule(state="Enabled"),
|
||||
"Policy2": MalwareRule(state="Disabled"),
|
||||
"Policy1": MalwareRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
),
|
||||
"Policy2": MalwareRule(
|
||||
state="Disabled",
|
||||
priority=2,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def mock_defender_get_antiphising_policy(_):
|
||||
def mock_defender_get_antiphishing_policy(_):
|
||||
return {
|
||||
"Policy1": AntiphishingPolicy(
|
||||
name="Policy1",
|
||||
spoof_intelligence=True,
|
||||
spoof_intelligence_action="Quarantine",
|
||||
dmarc_reject_action="Reject",
|
||||
@@ -60,6 +74,7 @@ def mock_defender_get_antiphising_policy(_):
|
||||
default=False,
|
||||
),
|
||||
"Policy2": AntiphishingPolicy(
|
||||
name="Policy2",
|
||||
spoof_intelligence=False,
|
||||
spoof_intelligence_action="None",
|
||||
dmarc_reject_action="None",
|
||||
@@ -73,13 +88,21 @@ def mock_defender_get_antiphising_policy(_):
|
||||
}
|
||||
|
||||
|
||||
def mock_defender_get_antiphising_rules(_):
|
||||
def mock_defender_get_antiphishing_rules(_):
|
||||
return {
|
||||
"Policy1": AntiphishingRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
),
|
||||
"Policy2": AntiphishingRule(
|
||||
state="Disabled",
|
||||
priority=2,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
),
|
||||
}
|
||||
|
||||
@@ -89,14 +112,35 @@ def mock_defender_get_inbound_spam_policy(_):
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Policy1",
|
||||
allowed_sender_domains=[],
|
||||
default=False,
|
||||
),
|
||||
DefenderInboundSpamPolicy(
|
||||
identity="Policy2",
|
||||
allowed_sender_domains=["example.com"],
|
||||
default=True,
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
def mock_defender_get_inbound_spam_rule(_):
|
||||
return {
|
||||
"Policy1": InboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
),
|
||||
"Policy2": InboundSpamRule(
|
||||
state="Disabled",
|
||||
priority=2,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def mock_defender_get_connection_filter_policy(_):
|
||||
return ConnectionFilterPolicy(
|
||||
ip_allow_list=[],
|
||||
@@ -131,6 +175,7 @@ def mock_defender_get_report_submission_policy(_):
|
||||
def mock_defender_get_outbound_spam_filter_policy(_):
|
||||
return {
|
||||
"Policy1": OutboundSpamPolicy(
|
||||
name="Policy1",
|
||||
notify_sender_blocked=True,
|
||||
notify_limit_exceeded=True,
|
||||
notify_limit_exceeded_addresses=["security@example.com"],
|
||||
@@ -139,6 +184,7 @@ def mock_defender_get_outbound_spam_filter_policy(_):
|
||||
default=False,
|
||||
),
|
||||
"Policy2": OutboundSpamPolicy(
|
||||
name="Policy2",
|
||||
notify_sender_blocked=False,
|
||||
notify_limit_exceeded=False,
|
||||
notify_limit_exceeded_addresses=[],
|
||||
@@ -153,9 +199,17 @@ def mock_defender_get_outbound_spam_filter_rule(_):
|
||||
return {
|
||||
"Policy1": OutboundSpamRule(
|
||||
state="Enabled",
|
||||
priority=1,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
),
|
||||
"Policy2": OutboundSpamRule(
|
||||
state="Disabled",
|
||||
priority=2,
|
||||
users=["test@example.com"],
|
||||
groups=["example_group"],
|
||||
domains=["example.com"],
|
||||
),
|
||||
}
|
||||
|
||||
@@ -230,14 +284,22 @@ class Test_Defender_Service:
|
||||
)
|
||||
malware_rules = defender_client.malware_rules
|
||||
assert malware_rules["Policy1"].state == "Enabled"
|
||||
assert malware_rules["Policy1"].priority == 1
|
||||
assert malware_rules["Policy1"].users == ["test@example.com"]
|
||||
assert malware_rules["Policy1"].groups == ["example_group"]
|
||||
assert malware_rules["Policy1"].domains == ["example.com"]
|
||||
assert malware_rules["Policy2"].state == "Disabled"
|
||||
assert malware_rules["Policy2"].priority == 2
|
||||
assert malware_rules["Policy2"].users == ["test@example.com"]
|
||||
assert malware_rules["Policy2"].groups == ["example_group"]
|
||||
assert malware_rules["Policy2"].domains == ["example.com"]
|
||||
defender_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.services.defender.defender_service.Defender._get_antiphising_policy",
|
||||
new=mock_defender_get_antiphising_policy,
|
||||
"prowler.providers.m365.services.defender.defender_service.Defender._get_antiphishing_policy",
|
||||
new=mock_defender_get_antiphishing_policy,
|
||||
)
|
||||
def test_get_antiphising_policy(self):
|
||||
def test_get_antiphishing_policy(self):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||
@@ -249,6 +311,7 @@ class Test_Defender_Service:
|
||||
)
|
||||
)
|
||||
antiphishing_policies = defender_client.antiphishing_policies
|
||||
assert antiphishing_policies["Policy1"].name == "Policy1"
|
||||
assert antiphishing_policies["Policy1"].spoof_intelligence is True
|
||||
assert (
|
||||
antiphishing_policies["Policy1"].spoof_intelligence_action
|
||||
@@ -265,6 +328,7 @@ class Test_Defender_Service:
|
||||
assert antiphishing_policies["Policy1"].show_tag is True
|
||||
assert antiphishing_policies["Policy1"].honor_dmarc_policy is True
|
||||
assert antiphishing_policies["Policy1"].default is False
|
||||
assert antiphishing_policies["Policy2"].name == "Policy2"
|
||||
assert antiphishing_policies["Policy2"].spoof_intelligence is False
|
||||
assert antiphishing_policies["Policy2"].spoof_intelligence_action == "None"
|
||||
assert antiphishing_policies["Policy2"].dmarc_reject_action == "None"
|
||||
@@ -279,10 +343,10 @@ class Test_Defender_Service:
|
||||
defender_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.services.defender.defender_service.Defender._get_antiphising_rules",
|
||||
new=mock_defender_get_antiphising_rules,
|
||||
"prowler.providers.m365.services.defender.defender_service.Defender._get_antiphishing_rules",
|
||||
new=mock_defender_get_antiphishing_rules,
|
||||
)
|
||||
def test_get_antiphising_rules(self):
|
||||
def test_get_antiphishing_rules(self):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||
@@ -293,9 +357,17 @@ class Test_Defender_Service:
|
||||
identity=M365IdentityInfo(tenant_domain=DOMAIN)
|
||||
)
|
||||
)
|
||||
antiphishing_rules = defender_client.antiphising_rules
|
||||
antiphishing_rules = defender_client.antiphishing_rules
|
||||
assert antiphishing_rules["Policy1"].state == "Enabled"
|
||||
assert antiphishing_rules["Policy1"].priority == 1
|
||||
assert antiphishing_rules["Policy1"].users == ["test@example.com"]
|
||||
assert antiphishing_rules["Policy1"].groups == ["example_group"]
|
||||
assert antiphishing_rules["Policy1"].domains == ["example.com"]
|
||||
assert antiphishing_rules["Policy2"].state == "Disabled"
|
||||
assert antiphishing_rules["Policy2"].priority == 2
|
||||
assert antiphishing_rules["Policy2"].users == ["test@example.com"]
|
||||
assert antiphishing_rules["Policy2"].groups == ["example_group"]
|
||||
assert antiphishing_rules["Policy2"].domains == ["example.com"]
|
||||
defender_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
@@ -357,6 +429,7 @@ class Test_Defender_Service:
|
||||
)
|
||||
)
|
||||
outbound_spam_policies = defender_client.outbound_spam_policies
|
||||
assert outbound_spam_policies["Policy1"].name == "Policy1"
|
||||
assert outbound_spam_policies["Policy1"].notify_sender_blocked is True
|
||||
assert outbound_spam_policies["Policy1"].notify_limit_exceeded is True
|
||||
assert outbound_spam_policies[
|
||||
@@ -367,6 +440,7 @@ class Test_Defender_Service:
|
||||
].notify_sender_blocked_addresses == ["security@example.com"]
|
||||
assert outbound_spam_policies["Policy1"].auto_forwarding_mode is False
|
||||
assert outbound_spam_policies["Policy1"].default is False
|
||||
assert outbound_spam_policies["Policy2"].name == "Policy2"
|
||||
assert outbound_spam_policies["Policy2"].notify_sender_blocked is False
|
||||
assert outbound_spam_policies["Policy2"].notify_limit_exceeded is False
|
||||
assert (
|
||||
@@ -377,6 +451,7 @@ class Test_Defender_Service:
|
||||
)
|
||||
assert outbound_spam_policies["Policy2"].auto_forwarding_mode is True
|
||||
assert outbound_spam_policies["Policy2"].default is True
|
||||
defender_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.services.defender.defender_service.Defender._get_outbound_spam_filter_rule",
|
||||
@@ -395,7 +470,16 @@ class Test_Defender_Service:
|
||||
)
|
||||
outbound_spam_rules = defender_client.outbound_spam_rules
|
||||
assert outbound_spam_rules["Policy1"].state == "Enabled"
|
||||
assert outbound_spam_rules["Policy1"].priority == 1
|
||||
assert outbound_spam_rules["Policy1"].users == ["test@example.com"]
|
||||
assert outbound_spam_rules["Policy1"].groups == ["example_group"]
|
||||
assert outbound_spam_rules["Policy1"].domains == ["example.com"]
|
||||
assert outbound_spam_rules["Policy2"].state == "Disabled"
|
||||
assert outbound_spam_rules["Policy2"].priority == 2
|
||||
assert outbound_spam_rules["Policy2"].users == ["test@example.com"]
|
||||
assert outbound_spam_rules["Policy2"].groups == ["example_group"]
|
||||
assert outbound_spam_rules["Policy2"].domains == ["example.com"]
|
||||
defender_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.services.defender.defender_service.Defender._get_inbound_spam_filter_policy",
|
||||
@@ -417,6 +501,34 @@ class Test_Defender_Service:
|
||||
assert inbound_spam_policies[1].allowed_sender_domains == ["example.com"]
|
||||
defender_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.services.defender.defender_service.Defender._get_inbound_spam_filter_rule",
|
||||
new=mock_defender_get_inbound_spam_rule,
|
||||
)
|
||||
def test__get_inbound_spam_filter_rule(self):
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.m365.lib.powershell.m365_powershell.M365PowerShell.connect_exchange_online"
|
||||
),
|
||||
):
|
||||
defender_client = Defender(
|
||||
set_mocked_m365_provider(
|
||||
identity=M365IdentityInfo(tenant_domain=DOMAIN)
|
||||
)
|
||||
)
|
||||
inbound_spam_rules = defender_client.inbound_spam_rules
|
||||
assert inbound_spam_rules["Policy1"].state == "Enabled"
|
||||
assert inbound_spam_rules["Policy1"].priority == 1
|
||||
assert inbound_spam_rules["Policy1"].users == ["test@example.com"]
|
||||
assert inbound_spam_rules["Policy1"].groups == ["example_group"]
|
||||
assert inbound_spam_rules["Policy1"].domains == ["example.com"]
|
||||
assert inbound_spam_rules["Policy2"].state == "Disabled"
|
||||
assert inbound_spam_rules["Policy2"].priority == 2
|
||||
assert inbound_spam_rules["Policy2"].users == ["test@example.com"]
|
||||
assert inbound_spam_rules["Policy2"].groups == ["example_group"]
|
||||
assert inbound_spam_rules["Policy2"].domains == ["example.com"]
|
||||
defender_client.powershell.close()
|
||||
|
||||
@patch(
|
||||
"prowler.providers.m365.services.defender.defender_service.Defender._get_report_submission_policy",
|
||||
new=mock_defender_get_report_submission_policy,
|
||||
|
||||
Reference in New Issue
Block a user