From 6da7730a297bbedbd966e696ce5df7a21c3fd295 Mon Sep 17 00:00:00 2001 From: Raymond Penners Date: Thu, 16 May 2024 22:49:08 +0200 Subject: [PATCH] fix: Don't import mfa/socialaccount models when not installed --- allauth/account/models.py | 3 +- .../account/tests/test_reauthentication.py | 5 + allauth/conftest.py | 4 +- tests/account_only/__init__.py | 0 tests/account_only/settings.py | 102 ++++++++++++++++++ tests/account_only/templates/429.html | 1 + tests/account_only/urls.py | 13 +++ 7 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 tests/account_only/__init__.py create mode 100644 tests/account_only/settings.py create mode 100644 tests/account_only/templates/429.html create mode 100644 tests/account_only/urls.py diff --git a/allauth/account/models.py b/allauth/account/models.py index 9cde931ab0..da22d66c06 100644 --- a/allauth/account/models.py +++ b/allauth/account/models.py @@ -275,7 +275,6 @@ def serialize(self): @classmethod def deserialize(cls, data): from allauth.account.utils import url_str_to_user_pk - from allauth.socialaccount.models import SocialLogin user = ( get_user_model() @@ -290,6 +289,8 @@ def deserialize(cls, data): if signal_kwargs is not None: sociallogin = signal_kwargs.get("sociallogin") if sociallogin is not None: + from allauth.socialaccount.models import SocialLogin + signal_kwargs = signal_kwargs.copy() signal_kwargs["sociallogin"] = SocialLogin.deserialize(sociallogin) diff --git a/allauth/account/tests/test_reauthentication.py b/allauth/account/tests/test_reauthentication.py index 7e598d818d..22f46acbff 100644 --- a/allauth/account/tests/test_reauthentication.py +++ b/allauth/account/tests/test_reauthentication.py @@ -5,6 +5,7 @@ import pytest from pytest_django.asserts import assertTemplateUsed +from allauth import app_settings as allauth_settings from allauth.account.adapter import get_adapter from allauth.account.authentication import AUTHENTICATION_METHODS_SESSION_KEY @@ -20,6 +21,8 @@ def test_user_with_mfa_only( user_factory, with_totp, with_password, expected_method_urlnames, client ): + if not allauth_settings.MFA_ENABLED and with_totp: + return user = user_factory(with_totp=with_totp, password=None if with_password else "!") assert user.has_usable_password() == with_password client.force_login(user) @@ -29,6 +32,8 @@ def test_user_with_mfa_only( map(reverse, expected_method_urlnames) ) for urlname in ["account_reauthenticate", "mfa_reauthenticate"]: + if urlname == "mfa_reauthenticate" and not allauth_settings.MFA_ENABLED: + continue resp = client.get(reverse(urlname) + "?next=/foo") if urlname in expected_method_urlnames: assert resp.status_code == 200 diff --git a/allauth/conftest.py b/allauth/conftest.py index 651f88dbc5..c74e83bd14 100644 --- a/allauth/conftest.py +++ b/allauth/conftest.py @@ -53,8 +53,6 @@ def user_password(password_factory): @pytest.fixture def user_factory(email_factory, db, user_password): - from allauth.mfa import totp - def factory( email=None, username=None, @@ -89,6 +87,8 @@ def factory( primary=True, ) if with_totp: + from allauth.mfa import totp + totp.TOTP.activate(user, totp.generate_totp_secret()) return user diff --git a/tests/account_only/__init__.py b/tests/account_only/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/account_only/settings.py b/tests/account_only/settings.py new file mode 100644 index 0000000000..3a8cacc65d --- /dev/null +++ b/tests/account_only/settings.py @@ -0,0 +1,102 @@ +from pathlib import Path + +from django.contrib.auth.hashers import PBKDF2PasswordHasher + + +SECRET_KEY = "psst" +SITE_ID = 1 +ALLOWED_HOSTS = ( + "testserver", + "example.com", +) +USE_I18N = False +USE_TZ = True + +DATABASES = { + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": ":memory:", + "USER": "", + "PASSWORD": "", + "HOST": "", + "PORT": "", + } +} + +ROOT_URLCONF = "tests.account_only.urls" +LOGIN_URL = "/login/" + +TEMPLATES = [ + { + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [Path(__file__).parent / "templates"], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", + ], + }, + }, +] + +CACHES = { + "default": { + "BACKEND": "django.core.cache.backends.dummy.DummyCache", + } +} + +MIDDLEWARE = ( + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", + "allauth.account.middleware.AccountMiddleware", +) + +INSTALLED_APPS = ( + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.sites", + "django.contrib.messages", + "django.contrib.staticfiles", + "django.contrib.admin", + "django.contrib.humanize", + "allauth", + "allauth.account", +) + +AUTHENTICATION_BACKENDS = ( + "django.contrib.auth.backends.ModelBackend", + "allauth.account.auth_backends.AuthenticationBackend", +) + +STATIC_ROOT = "/tmp/" # Dummy +STATIC_URL = "/static/" + + +class MyPBKDF2PasswordHasher(PBKDF2PasswordHasher): + """ + A subclass of PBKDF2PasswordHasher that uses 1 iteration. + + This is for test purposes only. Never use anywhere else. + """ + + iterations = 1 + + +PASSWORD_HASHERS = [ + "tests.headless_only.settings.MyPBKDF2PasswordHasher", + "django.contrib.auth.hashers.PBKDF2PasswordHasher", + "django.contrib.auth.hashers.PBKDF2SHA1PasswordHasher", + "django.contrib.auth.hashers.Argon2PasswordHasher", + "django.contrib.auth.hashers.BCryptSHA256PasswordHasher", +] + + +ACCOUNT_LOGIN_BY_CODE_ENABLED = True diff --git a/tests/account_only/templates/429.html b/tests/account_only/templates/429.html new file mode 100644 index 0000000000..3560666719 --- /dev/null +++ b/tests/account_only/templates/429.html @@ -0,0 +1 @@ +429 diff --git a/tests/account_only/urls.py b/tests/account_only/urls.py new file mode 100644 index 0000000000..29a5b717fd --- /dev/null +++ b/tests/account_only/urls.py @@ -0,0 +1,13 @@ +from django.contrib import admin +from django.urls import include, path + +from allauth.account.decorators import secure_admin_login + + +admin.autodiscover() +admin.site.login = secure_admin_login(admin.site.login) + +urlpatterns = [ + path("admin/", admin.site.urls), + path("", include("allauth.urls")), +]