auth: Accept next as POST parameter in POST requests.

Signed-off-by: Anders Kaseorg <anders@zulip.com>
This commit is contained in:
Anders Kaseorg
2020-05-14 19:13:33 -07:00
committed by Tim Abbott
parent 83380b4296
commit 620e98860e
4 changed files with 36 additions and 19 deletions

View File

@@ -15,13 +15,14 @@ page can be easily identified in it's respective JavaScript file -->
{% endif %} {% endif %}
<p class="devlogin_subheader">(Or visit the <a href="/login/">normal login page</a>.)</p> <p class="devlogin_subheader">(Or visit the <a href="/login/">normal login page</a>.)</p>
<form name="direct_login_form" id="direct_login_form" method="post" class="login-form"> <form name="direct_login_form" id="direct_login_form" method="post" class="login-form">
<input type="hidden" name="next" value="{{ next }}" />
<div class="control-group"> <div class="control-group">
<div class="controls"> <div class="controls">
<div class="group"> <div class="group">
<h2>{{ _('Administrators') }}</h2> <h2>{{ _('Administrators') }}</h2>
{% if direct_admins %} {% if direct_admins %}
{% for direct_admin in direct_admins %} {% for direct_admin in direct_admins %}
<p><input type="submit" formaction="{{ direct_admin.realm.uri }}{{ url('zerver.views.auth.dev_direct_login') }}?next={{ next }}" <p><input type="submit" formaction="{{ direct_admin.realm.uri }}{{ url('zerver.views.auth.dev_direct_login') }}"
name="direct_email" class="btn-direct btn-admin" value="{{ direct_admin.delivery_email }}" /></p> name="direct_email" class="btn-direct btn-admin" value="{{ direct_admin.delivery_email }}" /></p>
{% endfor %} {% endfor %}
{% else %} {% else %}
@@ -30,7 +31,7 @@ page can be easily identified in it's respective JavaScript file -->
<h2>{{ _('Guest users') }}</h2> <h2>{{ _('Guest users') }}</h2>
{% if guest_users %} {% if guest_users %}
{% for guest_user in guest_users %} {% for guest_user in guest_users %}
<p><input type="submit" formaction="{{ guest_user.realm.uri }}{{ url('zerver.views.auth.dev_direct_login') }}?next={{ next }}" <p><input type="submit" formaction="{{ guest_user.realm.uri }}{{ url('zerver.views.auth.dev_direct_login') }}"
name="direct_email" class="btn-direct btn-admin" value="{{ guest_user.delivery_email }}" /></p> name="direct_email" class="btn-direct btn-admin" value="{{ guest_user.delivery_email }}" /></p>
{% endfor %} {% endfor %}
{% else %} {% else %}
@@ -42,7 +43,7 @@ page can be easily identified in it's respective JavaScript file -->
<h2>{{ _('Normal users') }}</h2> <h2>{{ _('Normal users') }}</h2>
{% if direct_users %} {% if direct_users %}
{% for direct_user in direct_users %} {% for direct_user in direct_users %}
<p><input type="submit" formaction="{{ direct_user.realm.uri }}{{ url('zerver.views.auth.dev_direct_login') }}?next={{ next }}" <p><input type="submit" formaction="{{ direct_user.realm.uri }}{{ url('zerver.views.auth.dev_direct_login') }}"
name="direct_email" class="btn-direct btn-admin" value="{{ direct_user.delivery_email }}" /></p> name="direct_email" class="btn-direct btn-admin" value="{{ direct_user.delivery_email }}" /></p>
{% endfor %} {% endfor %}
{% else %} {% else %}

View File

@@ -41,7 +41,8 @@ page can be easily identified in it's respective JavaScript file. -->
{% else %} {% else %}
{% if password_auth_enabled %} {% if password_auth_enabled %}
<form name="login_form" id="login_form" method="post" class="login-form" <form name="login_form" id="login_form" method="post" class="login-form"
action="{{ url('django.contrib.auth.views.login') }}?next={{ next }}"> action="{{ url('django.contrib.auth.views.login') }}">
<input type="hidden" name="next" value="{{ next }}">
{% if two_factor_authentication_enabled %} {% if two_factor_authentication_enabled %}
{{ wizard.management_form }} {{ wizard.management_form }}

View File

@@ -2108,7 +2108,7 @@ class TestDevAuthBackend(ZulipTestCase):
with self.settings(TWO_FACTOR_AUTHENTICATION_ENABLED=True): with self.settings(TWO_FACTOR_AUTHENTICATION_ENABLED=True):
result = self.client_post('/accounts/login/local/', data) result = self.client_post('/accounts/login/local/', data)
self.assertEqual(result.status_code, 302) self.assertEqual(result.status_code, 302)
self.assertEqual(result.url, 'http://zulip.testserver') self.assertEqual(result.url, 'http://zulip.testserver/')
self.assert_logged_in_user_id(user_profile.id) self.assert_logged_in_user_id(user_profile.id)
self.assertIn('otp_device_id', list(self.client.session.keys())) self.assertIn('otp_device_id', list(self.client.session.keys()))
@@ -2120,7 +2120,7 @@ class TestDevAuthBackend(ZulipTestCase):
res = do_local_login('/accounts/login/local/') res = do_local_login('/accounts/login/local/')
self.assertEqual(res.status_code, 302) self.assertEqual(res.status_code, 302)
self.assertEqual(res.url, 'http://zulip.testserver') self.assertEqual(res.url, 'http://zulip.testserver/')
res = do_local_login('/accounts/login/local/?next=/user_uploads/path_to_image') res = do_local_login('/accounts/login/local/?next=/user_uploads/path_to_image')
self.assertEqual(res.status_code, 302) self.assertEqual(res.status_code, 302)

View File

@@ -251,8 +251,11 @@ def login_or_register_remote_user(request: HttpRequest, remote_username: str,
@log_view_func @log_view_func
@has_request_variables @has_request_variables
def remote_user_sso(request: HttpRequest, def remote_user_sso(
mobile_flow_otp: Optional[str]=REQ(default=None)) -> HttpResponse: request: HttpRequest,
mobile_flow_otp: Optional[str] = REQ(default=None),
next: str = REQ(default="/"),
) -> HttpResponse:
subdomain = get_subdomain(request) subdomain = get_subdomain(request)
try: try:
realm = get_realm(subdomain) # type: Optional[Realm] realm = get_realm(subdomain) # type: Optional[Realm]
@@ -286,11 +289,9 @@ def remote_user_sso(request: HttpRequest,
else: else:
user_profile = authenticate(remote_user=remote_user, realm=realm) user_profile = authenticate(remote_user=remote_user, realm=realm)
redirect_to = request.GET.get('next', '')
return login_or_register_remote_user(request, remote_user, user_profile, return login_or_register_remote_user(request, remote_user, user_profile,
mobile_flow_otp=mobile_flow_otp, mobile_flow_otp=mobile_flow_otp,
redirect_to=redirect_to) redirect_to=next)
@csrf_exempt @csrf_exempt
@log_view_func @log_view_func
@@ -338,9 +339,15 @@ def remote_user_jwt(request: HttpRequest) -> HttpResponse:
return login_or_register_remote_user(request, email, user_profile, remote_user) return login_or_register_remote_user(request, email, user_profile, remote_user)
def oauth_redirect_to_root(request: HttpRequest, url: str, @has_request_variables
sso_type: str, is_signup: bool=False, def oauth_redirect_to_root(
extra_url_params: Dict[str, str]={}) -> HttpResponse: request: HttpRequest,
url: str,
sso_type: str,
is_signup: bool=False,
extra_url_params: Dict[str, str]={},
next: Optional[str] = REQ(default=None),
) -> HttpResponse:
main_site_uri = settings.ROOT_DOMAIN_URI + url main_site_uri = settings.ROOT_DOMAIN_URI + url
if settings.SOCIAL_AUTH_SUBDOMAIN is not None and sso_type == 'social': if settings.SOCIAL_AUTH_SUBDOMAIN is not None and sso_type == 'social':
main_site_uri = (settings.EXTERNAL_URI_SCHEME + main_site_uri = (settings.EXTERNAL_URI_SCHEME +
@@ -363,7 +370,6 @@ def oauth_redirect_to_root(request: HttpRequest, url: str,
raise JsonableError(_("Invalid OTP")) raise JsonableError(_("Invalid OTP"))
params['mobile_flow_otp'] = mobile_flow_otp params['mobile_flow_otp'] = mobile_flow_otp
next = request.GET.get('next')
if next: if next:
params['next'] = next params['next'] = next
@@ -588,7 +594,9 @@ class TwoFactorLoginView(BaseTwoFactorLoginView):
realm = get_realm_from_request(self.request) realm = get_realm_from_request(self.request)
redirect_to = realm.uri if realm else '/' redirect_to = realm.uri if realm else '/'
context['next'] = self.request.GET.get('next', redirect_to) context['next'] = self.request.POST.get(
'next', self.request.GET.get('next', redirect_to),
)
return context return context
def done(self, form_list: List[Form], **kwargs: Any) -> HttpResponse: def done(self, form_list: List[Form], **kwargs: Any) -> HttpResponse:
@@ -609,7 +617,10 @@ class TwoFactorLoginView(BaseTwoFactorLoginView):
with patch.object(settings, 'LOGIN_REDIRECT_URL', realm_uri): with patch.object(settings, 'LOGIN_REDIRECT_URL', realm_uri):
return super().done(form_list, **kwargs) return super().done(form_list, **kwargs)
def login_page(request: HttpRequest, **kwargs: Any) -> HttpResponse: @has_request_variables
def login_page(
request: HttpRequest, next: str = REQ(default="/"), **kwargs: Any,
) -> HttpResponse:
# To support previewing the Zulip login pages, we have a special option # To support previewing the Zulip login pages, we have a special option
# that disables the default behavior of redirecting logged-in users to the # that disables the default behavior of redirecting logged-in users to the
# logged-in app. # logged-in app.
@@ -630,6 +641,7 @@ def login_page(request: HttpRequest, **kwargs: Any) -> HttpResponse:
return redirect_to_deactivation_notice() return redirect_to_deactivation_notice()
extra_context = kwargs.pop('extra_context', {}) extra_context = kwargs.pop('extra_context', {})
extra_context["next"] = next
if dev_auth_enabled() and kwargs.get("template_name") == "zerver/dev_login.html": if dev_auth_enabled() and kwargs.get("template_name") == "zerver/dev_login.html":
if 'new_realm' in request.POST: if 'new_realm' in request.POST:
try: try:
@@ -701,7 +713,11 @@ def start_two_factor_auth(request: HttpRequest,
return two_fa_view(request, **kwargs) return two_fa_view(request, **kwargs)
@csrf_exempt @csrf_exempt
def dev_direct_login(request: HttpRequest, **kwargs: Any) -> HttpResponse: @has_request_variables
def dev_direct_login(
request: HttpRequest,
next: str = REQ(default="/"),
) -> HttpResponse:
# This function allows logging in without a password and should only be called # This function allows logging in without a password and should only be called
# in development environments. It may be called if the DevAuthBackend is included # in development environments. It may be called if the DevAuthBackend is included
# in settings.AUTHENTICATION_BACKENDS # in settings.AUTHENTICATION_BACKENDS
@@ -717,7 +733,6 @@ def dev_direct_login(request: HttpRequest, **kwargs: Any) -> HttpResponse:
return HttpResponseRedirect(reverse('dev_not_supported')) return HttpResponseRedirect(reverse('dev_not_supported'))
do_login(request, user_profile) do_login(request, user_profile)
next = request.GET.get('next', '')
redirect_to = get_safe_redirect_to(next, user_profile.realm.uri) redirect_to = get_safe_redirect_to(next, user_profile.realm.uri)
return HttpResponseRedirect(redirect_to) return HttpResponseRedirect(redirect_to)