diff --git a/apps/users/tests/test_forms.py b/apps/users/tests/test_forms.py index 8c814848b..92332a1df 100644 --- a/apps/users/tests/test_forms.py +++ b/apps/users/tests/test_forms.py @@ -41,7 +41,8 @@ def test_duplicate_username(self): self.assertFalse(form.is_valid()) self.assertIn("username", form.errors) - def test_duplicate_email(self): + def test_duplicate_email_does_not_report_the_address_is_taken(self): + """Enumeration prevention keeps signup from confirming a known address.""" user = User.objects.create_user("test1", "test@example.com", "testpass") EmailAddress.objects.create(user=user, email="test@example.com") @@ -54,8 +55,8 @@ def test_duplicate_email(self): } ) - self.assertFalse(form.is_valid()) - self.assertIn("email", form.errors) + self.assertTrue(form.is_valid()) + self.assertNotIn("email", form.errors) def test_newline_in_username(self): # Note that since Django 1.9, forms.CharField().strip is True diff --git a/apps/users/tests/test_views.py b/apps/users/tests/test_views.py index 008802771..1c8109053 100644 --- a/apps/users/tests/test_views.py +++ b/apps/users/tests/test_views.py @@ -240,8 +240,22 @@ def test_user_duplicate_username_email(self): } self.assertUserCreated(data=post_data) response = self.assertUserCreated(data=post_data, template_name="account/signup.html") + # A taken username still has to be reported. A taken email must not be: + # enumeration prevention sends mail to the address instead. self.assertContains(response, "A user with that username already exists.") - self.assertContains(response, "A user is already registered with this email address.") + self.assertNotContains(response, "A user is already registered with this email address.") + + def test_password_reset_does_not_reveal_whether_the_email_is_known(self): + """An unknown address gets the same page as a known one.""" + url = reverse("account_reset_password") + + known = self.client.post(url, {"email": self.user.email}, follow=True) + unknown = self.client.post(url, {"email": "nobody@example.com"}, follow=True) + + self.assertEqual(known.status_code, 200) + self.assertEqual(unknown.status_code, 200) + self.assertEqual(known.redirect_chain, unknown.redirect_chain) + self.assertNotContains(unknown, "The email address is not assigned to any user account") def test_usernames(self): url = reverse("account_signup") diff --git a/pydotorg/settings/base.py b/pydotorg/settings/base.py index 0253506b7..711b4cd63 100644 --- a/pydotorg/settings/base.py +++ b/pydotorg/settings/base.py @@ -101,8 +101,7 @@ ACCOUNT_SIGNUP_FIELDS = ["email*", "username*", "password1*", "password2*"] ACCOUNT_UNIQUE_EMAIL = True ACCOUNT_EMAIL_VERIFICATION = "mandatory" -# TODO: Enable enumeration prevention -ACCOUNT_PREVENT_ENUMERATION = False +ACCOUNT_PREVENT_ENUMERATION = True SOCIALACCOUNT_EMAIL_REQUIRED = True SOCIALACCOUNT_EMAIL_VERIFICATION = True SOCIALACCOUNT_QUERY_EMAIL = True