diff --git a/api/changelog.d/social-account-linking.security.md b/api/changelog.d/social-account-linking.security.md index ab468dbefb..74e9fd129a 100644 --- a/api/changelog.d/social-account-linking.security.md +++ b/api/changelog.d/social-account-linking.security.md @@ -1 +1 @@ -Social account linking now requires a verified matching email from both the identity provider and the existing user account +Social account linking requires a verified matching email from both the identity provider and the existing user account without sending account connection notifications diff --git a/api/src/backend/api/adapters.py b/api/src/backend/api/adapters.py index d8c5b1b386..99ab88bf81 100644 --- a/api/src/backend/api/adapters.py +++ b/api/src/backend/api/adapters.py @@ -1,5 +1,3 @@ -import logging - from allauth.account.models import EmailAddress from allauth.core.exceptions import ImmediateHttpResponse from allauth.socialaccount.adapter import DefaultSocialAccountAdapter @@ -17,8 +15,6 @@ from api.utils import accept_invitation_for_user from django.db import transaction from django.http import HttpResponseForbidden -logger = logging.getLogger(__name__) - class ProwlerSocialAccountAdapter(DefaultSocialAccountAdapter): @staticmethod @@ -105,12 +101,6 @@ class ProwlerSocialAccountAdapter(DefaultSocialAccountAdapter): raise ImmediateHttpResponse(HttpResponseForbidden()) sociallogin.connect(request, existing_user) - def send_notification_mail(self, *args, **kwargs): - try: - return super().send_notification_mail(*args, **kwargs) - except OSError: - logger.exception("Failed to send social account connection notification") - def save_user(self, request, sociallogin, form=None): """ Called after the user data is fully populated from the provider diff --git a/api/src/backend/api/tests/test_adapters.py b/api/src/backend/api/tests/test_adapters.py index 70cd055205..c86d3f5620 100644 --- a/api/src/backend/api/tests/test_adapters.py +++ b/api/src/backend/api/tests/test_adapters.py @@ -302,7 +302,9 @@ class TestProwlerSocialAccountAdapter: sociallogin.connect.assert_called_once_with(request, create_test_user) - def test_verified_social_account_link_notifies_owner(self, create_test_user, rf): + def test_verified_social_account_link_does_not_send_notification( + self, create_test_user, rf + ): _verify_local_email(create_test_user) sociallogin = _real_oauth_sociallogin( create_test_user, @@ -318,34 +320,7 @@ class TestProwlerSocialAccountAdapter: uid="verified-google-account", user=create_test_user, ).exists() - assert len(mail.outbox) == 1 - assert mail.outbox[0].to == [create_test_user.email] - - def test_notification_delivery_failure_does_not_break_verified_link( - self, create_test_user, rf - ): - _verify_local_email(create_test_user) - sociallogin = _real_oauth_sociallogin( - create_test_user, - uid="verified-google-account-without-smtp", - ) - request = rf.get("/") - - with ( - context.request_context(request), - patch( - "allauth.socialaccount.adapter." - "DefaultSocialAccountAdapter.send_notification_mail", - side_effect=ConnectionRefusedError, - ), - ): - ProwlerSocialAccountAdapter().pre_social_login(request, sociallogin) - - assert SocialAccount.objects.filter( - provider="google", - uid="verified-google-account-without-smtp", - user=create_test_user, - ).exists() + assert mail.outbox == [] def test_pre_social_login_uses_verified_email_missing_from_extra_data( self, create_test_user, rf @@ -367,7 +342,7 @@ class TestProwlerSocialAccountAdapter: def test_social_account_linking_settings_are_fail_closed(self): assert not socialaccount_app_settings.EMAIL_AUTHENTICATION assert not socialaccount_app_settings.EMAIL_AUTHENTICATION_AUTO_CONNECT - assert account_app_settings.EMAIL_NOTIFICATIONS + assert not account_app_settings.EMAIL_NOTIFICATIONS def test_save_user_social_with_invitation_joins_invited_tenant( self, rf, create_test_user, tenants_fixture diff --git a/api/src/backend/config/settings/social_login.py b/api/src/backend/config/settings/social_login.py index 9ab3e89d73..ffc6a4724e 100644 --- a/api/src/backend/config/settings/social_login.py +++ b/api/src/backend/config/settings/social_login.py @@ -13,7 +13,7 @@ GITHUB_OAUTH_CALLBACK_URL = env("SOCIAL_GITHUB_OAUTH_CALLBACK_URL", default="") ACCOUNT_LOGIN_METHODS = {"email"} # Use Email / Password authentication ACCOUNT_SIGNUP_FIELDS = ["email*", "password1*", "password2*"] ACCOUNT_EMAIL_VERIFICATION = "none" # Do not require email confirmation -ACCOUNT_EMAIL_NOTIFICATIONS = True +ACCOUNT_EMAIL_NOTIFICATIONS = False ACCOUNT_USER_MODEL_USERNAME_FIELD = None REST_AUTH = { "TOKEN_MODEL": None,