diff --git a/templates/zerver/reset.html b/templates/zerver/reset.html index 80d2951877..d19819d566 100644 --- a/templates/zerver/reset.html +++ b/templates/zerver/reset.html @@ -12,7 +12,7 @@

Forgot your password? No problem, we'll send a link to reset your password to the email you signed up with.

-
+ {{ csrf_input }}
diff --git a/zerver/forms.py b/zerver/forms.py index 6b55b71ec8..9c34413382 100644 --- a/zerver/forms.py +++ b/zerver/forms.py @@ -210,8 +210,6 @@ class ZulipPasswordResetForm(PasswordResetForm): subdomain = get_subdomain(request) realm = get_realm(subdomain) - if realm is None: - raise ValidationError("Invalid realm") if not email_auth_enabled(realm): logging.info("Password reset attempted for %s even though password auth is disabled." % (email,)) diff --git a/zerver/tests/test_signup.py b/zerver/tests/test_signup.py index ee06c07369..1299ba7c79 100644 --- a/zerver/tests/test_signup.py +++ b/zerver/tests/test_signup.py @@ -227,19 +227,11 @@ class PasswordResetTest(ZulipTestCase): def test_wrong_subdomain(self): # type: () -> None email = self.example_email("hamlet") - string_id = 'hamlet' - name = 'Hamlet' - do_create_realm( - string_id, - name, - restricted_to_domain=False, - invite_required=False - ) - with patch('zerver.forms.get_subdomain', return_value=string_id): - # start the password reset process by supplying an email address - result = self.client_post( - '/accounts/password/reset/', {'email': email}) + # start the password reset process by supplying an email address + result = self.client_post( + '/accounts/password/reset/', {'email': email}, + subdomain="zephyr") # check the redirect link telling you to check mail for password reset link self.assertEqual(result.status_code, 302) @@ -258,31 +250,22 @@ class PasswordResetTest(ZulipTestCase): self.assertIn("hamlet@zulip.com does not have an active account in\nhttp://zephyr.testserver", message.body) - def test_correct_subdomain(self): + def test_invalid_subdomain(self): # type: () -> None email = self.example_email("hamlet") - string_id = 'zulip' - with patch('zerver.forms.get_subdomain', return_value=string_id): - # start the password reset process by supplying an email address - result = self.client_post( - '/accounts/password/reset/', {'email': email}) + # start the password reset process by supplying an email address + result = self.client_post( + '/accounts/password/reset/', {'email': email}, + subdomain="invalid") # check the redirect link telling you to check mail for password reset link - self.assertEqual(result.status_code, 302) - self.assertTrue(result["Location"].endswith( - "/accounts/password/reset/done/")) - result = self.client_get(result["Location"]) - - self.assert_in_response("Check your email to finish the process.", result) + self.assertEqual(result.status_code, 200) + self.assert_in_success_response(["There is no Zulip organization hosted at this subdomain."], + result) from django.core.mail import outbox - self.assertEqual(len(outbox), 1) - message = outbox.pop() - self.assertIn("Zulip Account Security", message.from_email) - self.assertIn(FromAddress.NOREPLY, message.from_email) - self.assertIn("Psst. Word on the street is that you", - message.body) + self.assertEqual(len(outbox), 0) @override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipLDAPAuthBackend', 'zproject.backends.ZulipDummyBackend')) diff --git a/zerver/views/auth.py b/zerver/views/auth.py index 874e8f01d8..f97f8d7b8a 100644 --- a/zerver/views/auth.py +++ b/zerver/views/auth.py @@ -5,6 +5,7 @@ from django.core.validators import validate_email from django.contrib.auth import authenticate, get_backends from django.contrib.auth.views import login as django_login_page, \ logout_then_login as django_logout_then_login +from django.contrib.auth.views import password_reset as django_password_reset from django.core.urlresolvers import reverse from zerver.decorator import authenticated_json_post_view, require_post, \ process_client, do_login, log_view_func @@ -22,7 +23,7 @@ from typing import Any, Dict, List, Optional, Tuple, Text from confirmation.models import Confirmation, create_confirmation_link from zerver.context_processors import zulip_default_context, get_realm_from_request from zerver.forms import HomepageForm, OurAuthenticationForm, \ - WRONG_SUBDOMAIN_ERROR + WRONG_SUBDOMAIN_ERROR, ZulipPasswordResetForm from zerver.lib.mobile_auth_otp import is_valid_otp, otp_encrypt_api_key from zerver.lib.request import REQ, has_request_variables, JsonableError from zerver.lib.response import json_success, json_error @@ -760,3 +761,17 @@ def api_fetch_google_client_id(request): def logout_then_login(request, **kwargs): # type: (HttpRequest, **Any) -> HttpResponse return django_logout_then_login(request, kwargs) + +def password_reset(request: HttpRequest, **kwargs: Any) -> HttpResponse: + realm = get_realm(get_subdomain(request)) + + if realm is None: + # If trying to get to password reset on a subdomain that + # doesn't exist, just go to find_account. + redirect_url = reverse('zerver.views.registration.find_account') + return HttpResponseRedirect(redirect_url) + + return django_password_reset(request, + template_name='zerver/reset.html', + password_reset_form=ZulipPasswordResetForm, + post_reset_redirect='/accounts/password/reset/done/') diff --git a/zproject/urls.py b/zproject/urls.py index 8803c98ec8..3b604fa886 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -13,8 +13,8 @@ from zerver.lib.integrations import WEBHOOK_INTEGRATIONS from zerver.webhooks import github_dispatcher -from django.contrib.auth.views import (login, password_reset, - password_reset_done, password_reset_confirm, password_reset_complete) +from django.contrib.auth.views import (login, password_reset_done, + password_reset_confirm, password_reset_complete) import zerver.tornado.views import zerver.views @@ -367,11 +367,8 @@ i18n_urls = [ zerver.views.zephyr.webathena_kerberos_login, name='zerver.views.zephyr.webathena_kerberos_login'), - url(r'^accounts/password/reset/$', password_reset, - {'post_reset_redirect': '/accounts/password/reset/done/', - 'template_name': 'zerver/reset.html', - 'password_reset_form': zerver.forms.ZulipPasswordResetForm, - }, name='django.contrib.auth.views.password_reset'), + url(r'^accounts/password/reset/$', zerver.views.auth.password_reset, + name='zerver.views.auth.password_reset'), url(r'^accounts/password/reset/done/$', password_reset_done, {'template_name': 'zerver/reset_emailed.html'}), url(r'^accounts/password/reset/(?P[0-9A-Za-z]+)/(?P.+)/$',