389 lines
14 KiB
Python
389 lines
14 KiB
Python
from __future__ import absolute_import
|
|
|
|
import django
|
|
from django import forms
|
|
from django.contrib.auth import get_user_model
|
|
from django.contrib.auth.models import AnonymousUser
|
|
from django.contrib.messages.middleware import MessageMiddleware
|
|
from django.contrib.sessions.middleware import SessionMiddleware
|
|
from django.core import mail
|
|
from django.test.client import Client, RequestFactory
|
|
from django.test.utils import override_settings
|
|
from django.urls import reverse
|
|
|
|
import pytest
|
|
from pytest_django.asserts import assertTemplateUsed
|
|
|
|
from allauth.account import app_settings
|
|
from allauth.account.adapter import get_adapter
|
|
from allauth.account.forms import BaseSignupForm, SignupForm
|
|
from allauth.account.models import EmailAddress
|
|
from allauth.core import context
|
|
from allauth.tests import TestCase
|
|
from allauth.utils import get_username_max_length
|
|
|
|
|
|
class CustomSignupFormTests(TestCase):
|
|
@override_settings(
|
|
ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE=True,
|
|
ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE=True,
|
|
)
|
|
def test_custom_form_field_order(self):
|
|
expected_field_order = [
|
|
"email",
|
|
"email2",
|
|
"password1",
|
|
"password2",
|
|
"username",
|
|
"last_name",
|
|
"first_name",
|
|
]
|
|
|
|
class TestSignupForm(forms.Form):
|
|
first_name = forms.CharField(max_length=30)
|
|
last_name = forms.CharField(max_length=30)
|
|
|
|
field_order = expected_field_order
|
|
|
|
class CustomSignupForm(SignupForm, TestSignupForm):
|
|
# ACCOUNT_SIGNUP_FORM_CLASS is only abided by when the
|
|
# BaseSignupForm definition is loaded the first time on Django
|
|
# startup. @override_settings() has therefore no effect.
|
|
pass
|
|
|
|
form = CustomSignupForm()
|
|
self.assertEqual(list(form.fields.keys()), expected_field_order)
|
|
|
|
def test_user_class_attribute(self):
|
|
from django.contrib.auth import get_user_model
|
|
from django.db.models.query_utils import DeferredAttribute
|
|
|
|
class CustomSignupForm(SignupForm):
|
|
# ACCOUNT_SIGNUP_FORM_CLASS is only abided by when the
|
|
# BaseSignupForm definition is loaded the first time on Django
|
|
# startup. @override_settings() has therefore no effect.
|
|
pass
|
|
|
|
User = get_user_model()
|
|
data = {
|
|
"username": "username",
|
|
"email": "user@example.com",
|
|
"password1": "very-secret",
|
|
"password2": "very-secret",
|
|
}
|
|
form = CustomSignupForm(data, email_required=True)
|
|
|
|
assert isinstance(User.username, DeferredAttribute)
|
|
form.is_valid()
|
|
assert isinstance(User.username, DeferredAttribute)
|
|
|
|
|
|
class BaseSignupFormTests(TestCase):
|
|
@override_settings(
|
|
ACCOUNT_USERNAME_REQUIRED=True, ACCOUNT_USERNAME_BLACKLIST=["username"]
|
|
)
|
|
def test_username_in_blacklist(self):
|
|
data = {
|
|
"username": "username",
|
|
"email": "user@example.com",
|
|
}
|
|
form = BaseSignupForm(data, email_required=True)
|
|
self.assertFalse(form.is_valid())
|
|
|
|
@override_settings(
|
|
ACCOUNT_USERNAME_REQUIRED=True, ACCOUNT_USERNAME_BLACKLIST=["username"]
|
|
)
|
|
def test_username_not_in_blacklist(self):
|
|
data = {
|
|
"username": "theusername",
|
|
"email": "user@example.com",
|
|
}
|
|
form = BaseSignupForm(data, email_required=True)
|
|
self.assertTrue(form.is_valid())
|
|
|
|
@override_settings(ACCOUNT_USERNAME_REQUIRED=True)
|
|
def test_username_maxlength(self):
|
|
data = {
|
|
"username": "username",
|
|
"email": "user@example.com",
|
|
}
|
|
form = BaseSignupForm(data, email_required=True)
|
|
max_length = get_username_max_length()
|
|
field = form.fields["username"]
|
|
self.assertEqual(field.max_length, max_length)
|
|
widget = field.widget
|
|
self.assertEqual(widget.attrs.get("maxlength"), str(max_length))
|
|
|
|
@override_settings(
|
|
ACCOUNT_USERNAME_REQUIRED=True, ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE=True
|
|
)
|
|
def test_signup_email_verification(self):
|
|
data = {
|
|
"username": "username",
|
|
"email": "user@example.com",
|
|
}
|
|
form = BaseSignupForm(data, email_required=True)
|
|
self.assertFalse(form.is_valid())
|
|
|
|
data = {
|
|
"username": "username",
|
|
"email": "user@example.com",
|
|
"email2": "user@example.com",
|
|
}
|
|
form = BaseSignupForm(data, email_required=True)
|
|
self.assertTrue(form.is_valid())
|
|
|
|
data["email2"] = "anotheruser@example.com"
|
|
form = BaseSignupForm(data, email_required=True)
|
|
self.assertFalse(form.is_valid())
|
|
|
|
|
|
@override_settings(
|
|
ACCOUNT_DEFAULT_HTTP_PROTOCOL="https",
|
|
ACCOUNT_EMAIL_VERIFICATION=app_settings.EmailVerificationMethod.MANDATORY,
|
|
ACCOUNT_AUTHENTICATION_METHOD=app_settings.AuthenticationMethod.USERNAME,
|
|
ACCOUNT_SIGNUP_FORM_CLASS=None,
|
|
ACCOUNT_EMAIL_SUBJECT_PREFIX=None,
|
|
LOGIN_REDIRECT_URL="/accounts/profile/",
|
|
ACCOUNT_SIGNUP_REDIRECT_URL="/accounts/welcome/",
|
|
ACCOUNT_ADAPTER="allauth.account.adapter.DefaultAccountAdapter",
|
|
ACCOUNT_USERNAME_REQUIRED=True,
|
|
)
|
|
class SignupTests(TestCase):
|
|
def test_signup_same_email_verified_externally(self):
|
|
user = self._test_signup_email_verified_externally(
|
|
"john@example.com", "john@example.com"
|
|
)
|
|
self.assertEqual(EmailAddress.objects.filter(user=user).count(), 1)
|
|
EmailAddress.objects.get(
|
|
verified=True, email="john@example.com", user=user, primary=True
|
|
)
|
|
|
|
def test_signup_other_email_verified_externally(self):
|
|
"""
|
|
John is invited on john@example.org, but signs up via john@example.com.
|
|
Email verification is by-passed, their home email address is
|
|
used as a secondary.
|
|
"""
|
|
user = self._test_signup_email_verified_externally(
|
|
"john@example.com", "john@example.org"
|
|
)
|
|
self.assertEqual(EmailAddress.objects.filter(user=user).count(), 2)
|
|
EmailAddress.objects.get(
|
|
verified=False, email="john@example.com", user=user, primary=False
|
|
)
|
|
EmailAddress.objects.get(
|
|
verified=True, email="john@example.org", user=user, primary=True
|
|
)
|
|
|
|
def _test_signup_email_verified_externally(self, signup_email, verified_email):
|
|
username = "johndoe"
|
|
request = RequestFactory().post(
|
|
reverse("account_signup"),
|
|
{
|
|
"username": username,
|
|
"email": signup_email,
|
|
"password1": "johndoe",
|
|
"password2": "johndoe",
|
|
},
|
|
)
|
|
# Fake stash_verified_email
|
|
SessionMiddleware(lambda request: None).process_request(request)
|
|
MessageMiddleware(lambda request: None).process_request(request)
|
|
request.user = AnonymousUser()
|
|
request.session["account_verified_email"] = verified_email
|
|
from allauth.account.views import signup
|
|
|
|
with context.request_context(request):
|
|
resp = signup(request)
|
|
self.assertEqual(resp.status_code, 302)
|
|
self.assertEqual(
|
|
resp["location"], get_adapter().get_signup_redirect_url(request)
|
|
)
|
|
self.assertEqual(len(mail.outbox), 0)
|
|
return get_user_model().objects.get(username=username)
|
|
|
|
@override_settings(
|
|
ACCOUNT_USERNAME_REQUIRED=True,
|
|
ACCOUNT_SIGNUP_PASSWORD_ENTER_TWICE=True,
|
|
)
|
|
def test_signup_password_twice_form_error(self):
|
|
resp = self.client.post(
|
|
reverse("account_signup"),
|
|
data={
|
|
"username": "johndoe",
|
|
"email": "john@example.org",
|
|
"password1": "johndoe",
|
|
"password2": "janedoe",
|
|
},
|
|
)
|
|
if django.VERSION >= (4, 1):
|
|
self.assertFormError(
|
|
resp.context["form"],
|
|
"password2",
|
|
"You must type the same password each time.",
|
|
)
|
|
else:
|
|
self.assertFormError(
|
|
resp,
|
|
"form",
|
|
"password2",
|
|
"You must type the same password each time.",
|
|
)
|
|
|
|
@override_settings(
|
|
ACCOUNT_USERNAME_REQUIRED=True, ACCOUNT_SIGNUP_EMAIL_ENTER_TWICE=True
|
|
)
|
|
def test_signup_email_twice(self):
|
|
request = RequestFactory().post(
|
|
reverse("account_signup"),
|
|
{
|
|
"username": "johndoe",
|
|
"email": "john@example.org",
|
|
"email2": "john@example.org",
|
|
"password1": "johndoe",
|
|
"password2": "johndoe",
|
|
},
|
|
)
|
|
SessionMiddleware(lambda request: None).process_request(request)
|
|
MessageMiddleware(lambda request: None).process_request(request)
|
|
request.user = AnonymousUser()
|
|
from allauth.account.views import signup
|
|
|
|
with context.request_context(request):
|
|
signup(request)
|
|
user = get_user_model().objects.get(username="johndoe")
|
|
self.assertEqual(user.email, "john@example.org")
|
|
|
|
@override_settings(
|
|
AUTH_PASSWORD_VALIDATORS=[
|
|
{
|
|
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
|
"OPTIONS": {
|
|
"min_length": 9,
|
|
},
|
|
}
|
|
]
|
|
)
|
|
def test_django_password_validation(self):
|
|
resp = self.client.post(
|
|
reverse("account_signup"),
|
|
{
|
|
"username": "johndoe",
|
|
"email": "john@example.com",
|
|
"password1": "johndoe",
|
|
"password2": "johndoe",
|
|
},
|
|
)
|
|
if django.VERSION >= (4, 1):
|
|
self.assertFormError(resp.context["form"], None, [])
|
|
self.assertFormError(
|
|
resp.context["form"],
|
|
"password1",
|
|
["This password is too short. It must contain at least 9 characters."],
|
|
)
|
|
else:
|
|
self.assertFormError(resp, "form", None, [])
|
|
self.assertFormError(
|
|
resp,
|
|
"form",
|
|
"password1",
|
|
["This password is too short. It must contain at least 9 characters."],
|
|
)
|
|
|
|
|
|
def test_prevent_enumeration_with_mandatory_verification(settings, user_factory):
|
|
settings.ACCOUNT_PREVENT_ENUMERATION = True
|
|
settings.ACCOUNT_AUTHENTICATION_METHOD = app_settings.AuthenticationMethod.EMAIL
|
|
settings.ACCOUNT_EMAIL_VERIFICATION = app_settings.EmailVerificationMethod.MANDATORY
|
|
user = user_factory(username="john", email="john@example.org", password="doe")
|
|
c = Client()
|
|
resp = c.post(
|
|
reverse("account_signup"),
|
|
{
|
|
"username": "johndoe",
|
|
"email": user.email,
|
|
"password1": "johndoe",
|
|
"password2": "johndoe",
|
|
},
|
|
)
|
|
assert resp.status_code == 302
|
|
assert resp["location"] == reverse("account_email_verification_sent")
|
|
assertTemplateUsed(resp, "account/email/account_already_exists_message.txt")
|
|
assert EmailAddress.objects.filter(email="john@example.org").count() == 1
|
|
|
|
|
|
def test_prevent_enumeration_off(settings, user_factory):
|
|
settings.ACCOUNT_PREVENT_ENUMERATION = False
|
|
settings.ACCOUNT_AUTHENTICATION_METHOD = app_settings.AuthenticationMethod.EMAIL
|
|
settings.ACCOUNT_EMAIL_VERIFICATION = app_settings.EmailVerificationMethod.MANDATORY
|
|
user = user_factory(username="john", email="john@example.org", password="doe")
|
|
c = Client()
|
|
resp = c.post(
|
|
reverse("account_signup"),
|
|
{
|
|
"username": "johndoe",
|
|
"email": user.email,
|
|
"password1": "johndoe",
|
|
"password2": "johndoe",
|
|
},
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.context["form"].errors == {
|
|
"email": ["A user is already registered with this email address."]
|
|
}
|
|
|
|
|
|
def test_prevent_enumeration_strictly(settings, user_factory):
|
|
settings.ACCOUNT_PREVENT_ENUMERATION = "strict"
|
|
settings.ACCOUNT_AUTHENTICATION_METHOD = app_settings.AuthenticationMethod.EMAIL
|
|
settings.ACCOUNT_EMAIL_VERIFICATION = app_settings.EmailVerificationMethod.NONE
|
|
user = user_factory(username="john", email="john@example.org", password="doe")
|
|
c = Client()
|
|
resp = c.post(
|
|
reverse("account_signup"),
|
|
{
|
|
"username": "johndoe",
|
|
"email": user.email,
|
|
"password1": "johndoe",
|
|
"password2": "johndoe",
|
|
},
|
|
)
|
|
assert resp.status_code == 302
|
|
assert resp["location"] == settings.LOGIN_REDIRECT_URL
|
|
assert EmailAddress.objects.filter(email="john@example.org").count() == 2
|
|
|
|
|
|
def test_prevent_enumeration_on(settings, user_factory):
|
|
settings.ACCOUNT_PREVENT_ENUMERATION = True
|
|
settings.ACCOUNT_AUTHENTICATION_METHOD = app_settings.AuthenticationMethod.EMAIL
|
|
settings.ACCOUNT_EMAIL_VERIFICATION = app_settings.EmailVerificationMethod.NONE
|
|
user = user_factory(username="john", email="john@example.org", password="doe")
|
|
c = Client()
|
|
resp = c.post(
|
|
reverse("account_signup"),
|
|
{
|
|
"username": "johndoe",
|
|
"email": user.email,
|
|
"password1": "johndoe",
|
|
"password2": "johndoe",
|
|
},
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.context["form"].errors == {
|
|
"email": ["A user is already registered with this email address."]
|
|
}
|
|
|
|
|
|
@pytest.mark.django_db
|
|
def test_get_initial_with_valid_email():
|
|
"""Test that the email field is populated with a valid email."""
|
|
request = RequestFactory().get("/signup/?email=test@example.com")
|
|
from allauth.account.views import signup
|
|
|
|
SessionMiddleware(lambda request: None).process_request(request)
|
|
request.user = AnonymousUser()
|
|
with context.request_context(request):
|
|
view = signup(request)
|
|
assert view.context_data["view"].get_initial()["email"] == "test@example.com"
|