diff --git a/prowler/changelog.d/googleworkspace-gmail-spoofing-fields.fixed.md b/prowler/changelog.d/googleworkspace-gmail-spoofing-fields.fixed.md new file mode 100644 index 0000000000..7ec9c0e189 --- /dev/null +++ b/prowler/changelog.d/googleworkspace-gmail-spoofing-fields.fixed.md @@ -0,0 +1 @@ +Gmail spoofing checks read each protection action from its own Policy API field; the inbound domain spoofing check could never pass and the similar domain names check reported the inbound action diff --git a/prowler/providers/googleworkspace/services/gmail/gmail_domain_spoofing_protection_enabled/gmail_domain_spoofing_protection_enabled.py b/prowler/providers/googleworkspace/services/gmail/gmail_domain_spoofing_protection_enabled/gmail_domain_spoofing_protection_enabled.py index 2eb169074f..e6535fbaaa 100644 --- a/prowler/providers/googleworkspace/services/gmail/gmail_domain_spoofing_protection_enabled/gmail_domain_spoofing_protection_enabled.py +++ b/prowler/providers/googleworkspace/services/gmail/gmail_domain_spoofing_protection_enabled/gmail_domain_spoofing_protection_enabled.py @@ -31,7 +31,7 @@ class gmail_domain_spoofing_protection_enabled(Check): ) enabled = gmail_client.policies.detect_domain_name_spoofing - consequence = gmail_client.policies.domain_spoofing_consequence + consequence = gmail_client.policies.domain_name_spoofing_consequence domain = gmail_client.provider.identity.domain if gmail_client.policies.off_for_everyone: diff --git a/prowler/providers/googleworkspace/services/gmail/gmail_service.py b/prowler/providers/googleworkspace/services/gmail/gmail_service.py index 4354255ff4..38076674bb 100644 --- a/prowler/providers/googleworkspace/services/gmail/gmail_service.py +++ b/prowler/providers/googleworkspace/services/gmail/gmail_service.py @@ -100,11 +100,14 @@ class Gmail(GoogleWorkspaceService): logger.debug("Gmail links and external images settings fetched.") elif setting_type == "gmail.spoofing_and_authentication": + # Each detect flag pairs with its own consequence: + # domainNameSpoofing is the similar-domain-names + # protection, domainSpoofing is the inbound one. self.policies.detect_domain_name_spoofing = value.get( "detectDomainNameSpoofing" ) - self.policies.domain_spoofing_consequence = value.get( - "domainSpoofingConsequence" + self.policies.domain_name_spoofing_consequence = value.get( + "domainNameSpoofingConsequence" ) self.policies.detect_employee_name_spoofing = value.get( "detectEmployeeNameSpoofing" @@ -116,7 +119,7 @@ class Gmail(GoogleWorkspaceService): "detectDomainSpoofingFromUnauthenticatedSenders" ) self.policies.inbound_domain_spoofing_consequence = value.get( - "inboundDomainSpoofingConsequence" + "domainSpoofingConsequence" ) self.policies.detect_unauthenticated_emails = value.get( "detectUnauthenticatedEmails" @@ -185,7 +188,7 @@ class GmailPolicies(ServicePolicies): # gmail.spoofing_and_authentication detect_domain_name_spoofing: Optional[bool] = None - domain_spoofing_consequence: Optional[str] = None + domain_name_spoofing_consequence: Optional[str] = None detect_employee_name_spoofing: Optional[bool] = None employee_name_spoofing_consequence: Optional[str] = None detect_inbound_domain_spoofing: Optional[bool] = None diff --git a/tests/providers/googleworkspace/services/gmail/gmail_domain_spoofing_protection_enabled/gmail_domain_spoofing_protection_enabled_test.py b/tests/providers/googleworkspace/services/gmail/gmail_domain_spoofing_protection_enabled/gmail_domain_spoofing_protection_enabled_test.py index 5c0d57d298..8d8fae0f82 100644 --- a/tests/providers/googleworkspace/services/gmail/gmail_domain_spoofing_protection_enabled/gmail_domain_spoofing_protection_enabled_test.py +++ b/tests/providers/googleworkspace/services/gmail/gmail_domain_spoofing_protection_enabled/gmail_domain_spoofing_protection_enabled_test.py @@ -29,7 +29,7 @@ class TestGmailDomainSpoofingProtectionEnabled: mock_client.policies_fetched = True mock_client.policies = GmailPolicies( detect_domain_name_spoofing=True, - domain_spoofing_consequence="SPAM_FOLDER", + domain_name_spoofing_consequence="SPAM_FOLDER", ) check = gmail_domain_spoofing_protection_enabled() @@ -60,7 +60,7 @@ class TestGmailDomainSpoofingProtectionEnabled: mock_client.provider = mock_provider mock_client.policies_fetched = True mock_client.policies = GmailPolicies( - domain_spoofing_consequence="SPAM_FOLDER", + domain_name_spoofing_consequence="SPAM_FOLDER", ) check = gmail_domain_spoofing_protection_enabled() @@ -93,7 +93,7 @@ class TestGmailDomainSpoofingProtectionEnabled: mock_client.policies_fetched = True mock_client.policies = GmailPolicies( detect_domain_name_spoofing=True, - domain_spoofing_consequence="NO_ACTION", + domain_name_spoofing_consequence="NO_ACTION", ) check = gmail_domain_spoofing_protection_enabled() @@ -123,7 +123,7 @@ class TestGmailDomainSpoofingProtectionEnabled: mock_client.policies_fetched = True mock_client.policies = GmailPolicies( detect_domain_name_spoofing=True, - domain_spoofing_consequence="WARNING", + domain_name_spoofing_consequence="WARNING", ) check = gmail_domain_spoofing_protection_enabled() @@ -153,7 +153,7 @@ class TestGmailDomainSpoofingProtectionEnabled: mock_client.policies_fetched = True mock_client.policies = GmailPolicies( detect_domain_name_spoofing=False, - domain_spoofing_consequence="WARNING", + domain_name_spoofing_consequence="WARNING", ) check = gmail_domain_spoofing_protection_enabled() diff --git a/tests/providers/googleworkspace/services/gmail/gmail_service_test.py b/tests/providers/googleworkspace/services/gmail/gmail_service_test.py index 6547b6f4fd..e17323756e 100644 --- a/tests/providers/googleworkspace/services/gmail/gmail_service_test.py +++ b/tests/providers/googleworkspace/services/gmail/gmail_service_test.py @@ -58,11 +58,11 @@ class TestGmailService: "type": "settings/gmail.spoofing_and_authentication", "value": { "detectDomainNameSpoofing": True, - "domainSpoofingConsequence": "SPAM_FOLDER", + "domainNameSpoofingConsequence": "SPAM_FOLDER", "detectEmployeeNameSpoofing": True, "employeeNameSpoofingConsequence": "SPAM_FOLDER", "detectDomainSpoofingFromUnauthenticatedSenders": True, - "inboundDomainSpoofingConsequence": "QUARANTINE", + "domainSpoofingConsequence": "QUARANTINE", "detectUnauthenticatedEmails": True, "unauthenticatedEmailConsequence": "WARNING", "detectGroupsSpoofing": True, @@ -146,7 +146,7 @@ class TestGmailService: assert gmail.policies.enable_external_image_scanning is True assert gmail.policies.enable_aggressive_warnings_on_untrusted_links is True assert gmail.policies.detect_domain_name_spoofing is True - assert gmail.policies.domain_spoofing_consequence == "SPAM_FOLDER" + assert gmail.policies.domain_name_spoofing_consequence == "SPAM_FOLDER" assert gmail.policies.detect_employee_name_spoofing is True assert gmail.policies.employee_name_spoofing_consequence == "SPAM_FOLDER" assert gmail.policies.detect_inbound_domain_spoofing is True @@ -320,6 +320,67 @@ class TestGmailService: assert fetched.policies.service_state_overridden is True assert fetched.policies.off_for_everyone is False + def test_each_spoofing_action_is_read_from_its_own_field(self): + """The API pairs each detect flag with a consequence: domainNameSpoofing + for similar domain names and domainSpoofing for inbound emails spoofing + the domain. Reading the wrong one left the inbound check unable to pass + and the similar-names check reporting the inbound action.""" + mock_provider = set_mocked_googleworkspace_provider() + mock_provider.audit_config = {} + mock_provider.fixer_config = {} + mock_session = MagicMock() + mock_session.credentials = MagicMock() + mock_provider.session = mock_session + + mock_service = MagicMock() + mock_policies_list = MagicMock() + mock_policies_list.execute.return_value = { + "policies": [ + { + "setting": { + "type": "settings/gmail.spoofing_and_authentication", + "value": { + "detectDomainNameSpoofing": True, + "domainNameSpoofingConsequence": "WARNING", + "detectEmployeeNameSpoofing": True, + "employeeNameSpoofingConsequence": "QUARANTINE", + "detectDomainSpoofingFromUnauthenticatedSenders": True, + "domainSpoofingConsequence": "SPAM_FOLDER", + "detectUnauthenticatedEmails": False, + "unauthenticatedEmailConsequence": "NO_ACTION", + "detectGroupsSpoofing": True, + "groupsSpoofingVisibilityType": "ALL_GROUPS", + "groupsSpoofingConsequence": "QUARANTINE", + }, + } + }, + ] + } + mock_service.policies().list.return_value = mock_policies_list + mock_service.policies().list_next.return_value = None + + with ( + patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=mock_provider, + ), + patch( + "prowler.providers.googleworkspace.services.gmail.gmail_service.GoogleWorkspaceService._build_service", + return_value=mock_service, + ), + ): + from prowler.providers.googleworkspace.services.gmail.gmail_service import ( + Gmail, + ) + + gmail = Gmail(mock_provider) + + assert gmail.policies.domain_name_spoofing_consequence == "WARNING" + assert gmail.policies.employee_name_spoofing_consequence == "QUARANTINE" + assert gmail.policies.inbound_domain_spoofing_consequence == "SPAM_FOLDER" + assert gmail.policies.unauthenticated_email_consequence == "NO_ACTION" + assert gmail.policies.groups_spoofing_consequence == "QUARANTINE" + def test_gmail_fetch_policies_empty_response(self): """Test handling empty policies response""" mock_provider = set_mocked_googleworkspace_provider() @@ -648,7 +709,7 @@ class TestGmailService: enable_external_image_scanning=True, enable_aggressive_warnings_on_untrusted_links=True, detect_domain_name_spoofing=True, - domain_spoofing_consequence="SPAM_FOLDER", + domain_name_spoofing_consequence="SPAM_FOLDER", detect_employee_name_spoofing=True, employee_name_spoofing_consequence="SPAM_FOLDER", detect_inbound_domain_spoofing=True, @@ -670,7 +731,7 @@ class TestGmailService: assert policies.encrypted_attachment_protection_consequence == "SPAM_FOLDER" assert policies.enable_shortener_scanning is True assert policies.detect_domain_name_spoofing is True - assert policies.domain_spoofing_consequence == "SPAM_FOLDER" + assert policies.domain_name_spoofing_consequence == "SPAM_FOLDER" assert policies.enable_pop_access is False assert policies.enable_auto_forwarding is False assert policies.enable_enhanced_pre_delivery_scanning is True