From dcee114ef3b428a9480375f838e99314a9c81beb Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Mon, 11 Aug 2025 09:42:30 +0200 Subject: [PATCH] fix: validation errors in azure and m365 (#8368) --- prowler/CHANGELOG.md | 1 + .../admincenter/admincenter_service.py | 33 ++++++---- ...pam_outbound_policy_forwarding_disabled.py | 2 +- .../services/defender/defender_service.py | 60 +++++++++++++++++-- .../services/exchange/exchange_service.py | 12 +++- ...ntispam_outbound_policy_configured_test.py | 20 +++---- ...utbound_policy_forwarding_disabled_test.py | 20 +++---- .../defender/m365_defender_service_test.py | 8 +-- 8 files changed, 111 insertions(+), 45 deletions(-) diff --git a/prowler/CHANGELOG.md b/prowler/CHANGELOG.md index cf2e158655..07e798ae8b 100644 --- a/prowler/CHANGELOG.md +++ b/prowler/CHANGELOG.md @@ -17,6 +17,7 @@ All notable changes to the **Prowler SDK** are documented in this file. ### Fixed - Order requirements by ID in Prowler ThreatScore AWS compliance framework [(#8495)](https://github.com/prowler-cloud/prowler/pull/8495) +- Validation errors in Azure and M365 providers [(#8353)](https://github.com/prowler-cloud/prowler/pull/8353) --- diff --git a/prowler/providers/m365/services/admincenter/admincenter_service.py b/prowler/providers/m365/services/admincenter/admincenter_service.py index 3a3e1f3284..1cd85faa2e 100644 --- a/prowler/providers/m365/services/admincenter/admincenter_service.py +++ b/prowler/providers/m365/services/admincenter/admincenter_service.py @@ -87,9 +87,11 @@ class AdminCenter(M365Service): { user.id: User( id=user.id, - name=user.display_name, + name=getattr(user, "display_name", ""), license=( - license_details.value[0].sku_part_number + getattr( + license_details.value[0], "sku_part_number", None + ) if license_details.value else None ), @@ -149,8 +151,8 @@ class AdminCenter(M365Service): { group.id: Group( id=group.id, - name=group.display_name, - visibility=group.visibility, + name=getattr(group, "display_name", ""), + visibility=getattr(group, "visibility", ""), ) } ) @@ -168,14 +170,21 @@ class AdminCenter(M365Service): domains_list = await self.client.domains.get() domains.update({}) for domain in domains_list.value: - domains.update( - { - domain.id: Domain( - id=domain.id, - password_validity_period=domain.password_validity_period_in_days, - ) - } - ) + if domain: + password_validity_period = getattr( + domain, "password_validity_period_in_days", None + ) + if password_validity_period is None: + password_validity_period = 0 + + domains.update( + { + domain.id: Domain( + id=domain.id, + password_validity_period=password_validity_period, + ) + } + ) except Exception as error: logger.error( diff --git a/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled.py b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled.py index 04f81f62b3..b0530c4308 100644 --- a/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled.py +++ b/prowler/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled.py @@ -166,4 +166,4 @@ class defender_antispam_outbound_policy_forwarding_disabled(Check): policy.default or defender_client.outbound_spam_rules[policy.name].state.lower() == "enabled" - ) and not policy.auto_forwarding_mode + ) and policy.auto_forwarding_mode == "Off" diff --git a/prowler/providers/m365/services/defender/defender_service.py b/prowler/providers/m365/services/defender/defender_service.py index cdfd53a6b7..5d198b5888 100644 --- a/prowler/providers/m365/services/defender/defender_service.py +++ b/prowler/providers/m365/services/defender/defender_service.py @@ -44,6 +44,23 @@ class Defender(M365Service): malware_policy = [malware_policy] for policy in malware_policy: if policy: + file_types_raw = policy.get("FileTypes", []) + file_types = [] + if file_types_raw is not None: + if isinstance(file_types_raw, list): + file_types = file_types_raw + else: + try: + if isinstance(file_types_raw, str): + file_types = [file_types_raw] + else: + file_types = [str(file_types_raw)] + except (ValueError, TypeError): + logger.warning( + f"Skipping invalid file_types value: {file_types_raw}" + ) + file_types = [] + malware_policies.append( MalwarePolicy( enable_file_filter=policy.get("EnableFileFilter", False), @@ -54,7 +71,7 @@ class Defender(M365Service): internal_sender_admin_address=policy.get( "InternalSenderAdminAddress", "" ), - file_types=policy.get("FileTypes", []), + file_types=file_types, is_default=policy.get("IsDefault", False), ) ) @@ -207,7 +224,7 @@ class Defender(M365Service): notify_sender_blocked_addresses=policy.get( "NotifyOutboundSpamRecipients", [] ), - auto_forwarding_mode=policy.get("AutoForwardingMode", True), + auto_forwarding_mode=policy.get("AutoForwardingMode", "On"), default=policy.get("IsDefault", False), ) @@ -257,12 +274,43 @@ class Defender(M365Service): inbound_spam_policy = [inbound_spam_policy] for policy in inbound_spam_policy: if policy: + allowed_domains_raw = policy.get("AllowedSenderDomains", []) + allowed_domains = [] + + if isinstance(allowed_domains_raw, str): + try: + import json + + parsed_domains = json.loads(allowed_domains_raw) + if isinstance(parsed_domains, list): + allowed_domains_raw = parsed_domains + else: + logger.warning( + f"Expected list from JSON string, got: {type(parsed_domains)}" + ) + allowed_domains_raw = [] + except (json.JSONDecodeError, ValueError) as e: + logger.warning( + f"Failed to parse AllowedSenderDomains as JSON: {e}" + ) + allowed_domains_raw = [] + + if allowed_domains_raw: + for domain in allowed_domains_raw: + if isinstance(domain, str): + allowed_domains.append(domain) + else: + try: + allowed_domains.append(str(domain)) + except (ValueError, TypeError): + logger.warning( + f"Skipping invalid domain value: {domain}" + ) + inbound_spam_policies.append( DefenderInboundSpamPolicy( identity=policy.get("Identity", ""), - allowed_sender_domains=policy.get( - "AllowedSenderDomains", [] - ), + allowed_sender_domains=allowed_domains, default=policy.get("IsDefault", False), ) ) @@ -389,7 +437,7 @@ class OutboundSpamPolicy(BaseModel): notify_limit_exceeded: bool notify_limit_exceeded_addresses: List[str] notify_sender_blocked_addresses: List[str] - auto_forwarding_mode: bool + auto_forwarding_mode: str default: bool diff --git a/prowler/providers/m365/services/exchange/exchange_service.py b/prowler/providers/m365/services/exchange/exchange_service.py index 96bbd4e13c..35d4068007 100644 --- a/prowler/providers/m365/services/exchange/exchange_service.py +++ b/prowler/providers/m365/services/exchange/exchange_service.py @@ -123,12 +123,20 @@ class Exchange(M365Service): rules_data = [rules_data] for rule in rules_data: if rule: + sender_domain_is = rule.get("SenderDomainIs", []) + if sender_domain_is is None: + sender_domain_is = [] + + redirect_message_to = rule.get("RedirectMessageTo", []) + if redirect_message_to is None: + redirect_message_to = [] + transport_rules.append( TransportRule( name=rule.get("Name", ""), scl=rule.get("SetSCL", None), - sender_domain_is=rule.get("SenderDomainIs", []), - redirect_message_to=rule.get("RedirectMessageTo", None), + sender_domain_is=sender_domain_is, + redirect_message_to=redirect_message_to, ) ) except Exception as error: diff --git a/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py index 7baedbeb61..c3200b2e36 100644 --- a/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py +++ b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_configured/defender_antispam_outbound_policy_configured_test.py @@ -36,7 +36,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], notify_sender_blocked_addresses=["admin@example.com"], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=True, ) } @@ -93,7 +93,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], notify_sender_blocked_addresses=["admin@example.com"], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=True, ), "Policy1": OutboundSpamPolicy( @@ -102,7 +102,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], notify_sender_blocked_addresses=["admin@example.com"], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=False, ), } @@ -177,7 +177,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], notify_sender_blocked_addresses=["admin@example.com"], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=True, ), "Policy1": OutboundSpamPolicy( @@ -186,7 +186,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=False, notify_limit_exceeded_addresses=[], notify_sender_blocked_addresses=[], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=False, ), } @@ -261,7 +261,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=False, notify_limit_exceeded_addresses=[], notify_sender_blocked_addresses=[], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=True, ), "Policy1": OutboundSpamPolicy( @@ -270,7 +270,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], notify_sender_blocked_addresses=["admin@example.com"], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=False, ), } @@ -344,7 +344,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=False, notify_limit_exceeded_addresses=[], notify_sender_blocked_addresses=[], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=True, ) } @@ -398,7 +398,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=False, notify_limit_exceeded_addresses=[], notify_sender_blocked_addresses=[], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=True, ), "Policy1": OutboundSpamPolicy( @@ -407,7 +407,7 @@ class Test_defender_antispam_outbound_policy_configured: notify_sender_blocked=False, notify_limit_exceeded_addresses=[], notify_sender_blocked_addresses=[], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=False, ), } diff --git a/tests/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled_test.py b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled_test.py index 64fce5f88b..72f5c104ff 100644 --- a/tests/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled_test.py +++ b/tests/providers/m365/services/defender/defender_antispam_outbound_policy_forwarding_disabled/defender_antispam_outbound_policy_forwarding_disabled_test.py @@ -32,7 +32,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: defender_client.outbound_spam_policies = { "Default": OutboundSpamPolicy( name="Default", - auto_forwarding_mode=False, + auto_forwarding_mode="Off", notify_limit_exceeded=True, notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], @@ -86,7 +86,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: defender_client.outbound_spam_policies = { "Default": OutboundSpamPolicy( name="Default", - auto_forwarding_mode=False, + auto_forwarding_mode="Off", notify_limit_exceeded=True, notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], @@ -95,7 +95,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: ), "Policy1": OutboundSpamPolicy( name="Policy1", - auto_forwarding_mode=False, + auto_forwarding_mode="Off", notify_limit_exceeded=True, notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], @@ -172,7 +172,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: defender_client.outbound_spam_policies = { "Default": OutboundSpamPolicy( name="Default", - auto_forwarding_mode=False, + auto_forwarding_mode="Off", notify_limit_exceeded=True, notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], @@ -181,7 +181,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: ), "Policy1": OutboundSpamPolicy( name="Policy1", - auto_forwarding_mode=True, + auto_forwarding_mode="On", notify_limit_exceeded=False, notify_sender_blocked=False, notify_limit_exceeded_addresses=[], @@ -258,7 +258,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: defender_client.outbound_spam_policies = { "Default": OutboundSpamPolicy( name="Default", - auto_forwarding_mode=True, + auto_forwarding_mode="On", notify_limit_exceeded=False, notify_sender_blocked=False, notify_limit_exceeded_addresses=[], @@ -267,7 +267,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: ), "Policy1": OutboundSpamPolicy( name="Policy1", - auto_forwarding_mode=False, + auto_forwarding_mode="Off", notify_limit_exceeded=True, notify_sender_blocked=True, notify_limit_exceeded_addresses=["admin@example.com"], @@ -343,7 +343,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: defender_client.outbound_spam_policies = { "Default": OutboundSpamPolicy( name="Default", - auto_forwarding_mode=True, + auto_forwarding_mode="On", notify_limit_exceeded=False, notify_sender_blocked=False, notify_limit_exceeded_addresses=[], @@ -397,7 +397,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: defender_client.outbound_spam_policies = { "Default": OutboundSpamPolicy( name="Default", - auto_forwarding_mode=True, + auto_forwarding_mode="On", notify_limit_exceeded=False, notify_sender_blocked=False, notify_limit_exceeded_addresses=[], @@ -406,7 +406,7 @@ class Test_defender_antispam_outbound_policy_forwarding_disabled: ), "Policy1": OutboundSpamPolicy( name="Policy1", - auto_forwarding_mode=True, + auto_forwarding_mode="On", notify_limit_exceeded=False, notify_sender_blocked=False, notify_limit_exceeded_addresses=[], diff --git a/tests/providers/m365/services/defender/m365_defender_service_test.py b/tests/providers/m365/services/defender/m365_defender_service_test.py index 35534a53e3..a78cc4b10a 100644 --- a/tests/providers/m365/services/defender/m365_defender_service_test.py +++ b/tests/providers/m365/services/defender/m365_defender_service_test.py @@ -180,7 +180,7 @@ def mock_defender_get_outbound_spam_filter_policy(_): notify_limit_exceeded=True, notify_limit_exceeded_addresses=["security@example.com"], notify_sender_blocked_addresses=["security@example.com"], - auto_forwarding_mode=False, + auto_forwarding_mode="Off", default=False, ), "Policy2": OutboundSpamPolicy( @@ -189,7 +189,7 @@ def mock_defender_get_outbound_spam_filter_policy(_): notify_limit_exceeded=False, notify_limit_exceeded_addresses=[], notify_sender_blocked_addresses=[], - auto_forwarding_mode=True, + auto_forwarding_mode="On", default=True, ), } @@ -438,7 +438,7 @@ class Test_Defender_Service: assert outbound_spam_policies[ "Policy1" ].notify_sender_blocked_addresses == ["security@example.com"] - assert outbound_spam_policies["Policy1"].auto_forwarding_mode is False + assert outbound_spam_policies["Policy1"].auto_forwarding_mode == "Off" 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 @@ -449,7 +449,7 @@ class Test_Defender_Service: assert ( outbound_spam_policies["Policy2"].notify_sender_blocked_addresses == [] ) - assert outbound_spam_policies["Policy2"].auto_forwarding_mode is True + assert outbound_spam_policies["Policy2"].auto_forwarding_mode == "On" assert outbound_spam_policies["Policy2"].default is True defender_client.powershell.close()