mirror of
https://github.com/zulip/zulip.git
synced 2025-11-03 21:43:21 +00:00
auth: Only automatically redirect for same domain redirects.
If the `deactivated_redirect` belongs to the same domain as `EXTERNAL_HOST`, automatically redirect, otherwise just point user to the new URL.
This commit is contained in:
@@ -605,6 +605,7 @@ def support(
|
||||
if parse_result.port:
|
||||
hostname = f"{hostname}:{parse_result.port}"
|
||||
subdomain = get_subdomain_from_hostname(hostname)
|
||||
assert subdomain is not None
|
||||
with suppress(Realm.DoesNotExist):
|
||||
realms.add(get_realm(subdomain))
|
||||
except ValidationError:
|
||||
|
||||
@@ -16,12 +16,25 @@
|
||||
<div class="inline-block">
|
||||
|
||||
<div class="get-started">
|
||||
<h1>{{ _("Deactivated organization") }}</h1>
|
||||
{% if deactivated_redirect %}
|
||||
<h1>{{ _("Organization moved") }}</h1>
|
||||
{% else %}
|
||||
<h1>{{ _("Deactivated organization") }}</h1>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="white-box deactivated-realm-container">
|
||||
<p>
|
||||
{% if realm_data_deleted %}
|
||||
{% if deactivated_redirect %}
|
||||
{% trans %}
|
||||
This organization has moved to <a href="{{ deactivated_redirect }}">{{ deactivated_redirect }}</a>.
|
||||
{% endtrans %}
|
||||
{% if auto_redirect_to %}
|
||||
{% trans %}
|
||||
This page will automatically redirect to the <a href="{{ auto_redirect_to }}" id="deactivated-org-auto-redirect">new URL</a> in <span id="deactivated-org-auto-redirect-countdown">5</span> seconds.
|
||||
{% endtrans %}
|
||||
{% endif %}
|
||||
{% elif realm_data_deleted %}
|
||||
{{ _("This organization has been deactivated, and all organization data has been deleted.") }}
|
||||
{% if corporate_enabled %}
|
||||
{% trans %}
|
||||
|
||||
@@ -493,4 +493,19 @@ $(() => {
|
||||
$("#slack-access-token").on("input", () => {
|
||||
$("#update-slack-access-token").show();
|
||||
});
|
||||
|
||||
if ($("a#deactivated-org-auto-redirect").length > 0) {
|
||||
// This is a special case for the deactivated organization page,
|
||||
// where we want to redirect to the login page after 5 seconds.
|
||||
const interval_id = setInterval(() => {
|
||||
const $countdown_elt = $("#deactivated-org-auto-redirect-countdown");
|
||||
const current_countdown = Number($countdown_elt.text());
|
||||
if (current_countdown > 0) {
|
||||
$countdown_elt.text((current_countdown - 1).toString());
|
||||
} else {
|
||||
window.location.href = $("a#deactivated-org-auto-redirect").attr("href")!;
|
||||
clearInterval(interval_id);
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -22,22 +22,27 @@ def get_subdomain(request: HttpRequest) -> str:
|
||||
# compatibility with older versions of Zulip, so that's a start.
|
||||
|
||||
host = request.get_host().lower()
|
||||
return get_subdomain_from_hostname(host)
|
||||
subdomain = get_subdomain_from_hostname(host)
|
||||
assert subdomain is not None
|
||||
return subdomain
|
||||
|
||||
|
||||
def get_subdomain_from_hostname(host: str) -> str:
|
||||
def get_subdomain_from_hostname(
|
||||
host: str, default_subdomain: str | None = Realm.SUBDOMAIN_FOR_ROOT_DOMAIN
|
||||
) -> str | None:
|
||||
# Set `default_subdomain` as None to check if a valid subdomain was found.
|
||||
m = re.search(rf"\.{settings.EXTERNAL_HOST}(:\d+)?$", host)
|
||||
if m:
|
||||
subdomain = host[: m.start()]
|
||||
if subdomain in settings.ROOT_SUBDOMAIN_ALIASES:
|
||||
return Realm.SUBDOMAIN_FOR_ROOT_DOMAIN
|
||||
return default_subdomain
|
||||
return subdomain
|
||||
|
||||
for subdomain, realm_host in settings.REALM_HOSTS.items():
|
||||
if re.search(rf"^{realm_host}(:\d+)?$", host):
|
||||
return subdomain
|
||||
|
||||
return Realm.SUBDOMAIN_FOR_ROOT_DOMAIN
|
||||
return default_subdomain
|
||||
|
||||
|
||||
def is_subdomain_root_or_alias(request: HttpRequest) -> bool:
|
||||
|
||||
@@ -191,14 +191,19 @@ class DeactivationNoticeTestCase(ZulipTestCase):
|
||||
realm.save(update_fields=["deactivated", "deactivated_redirect"])
|
||||
|
||||
result = self.client_get("/login/", follow=True)
|
||||
self.assertIn(result.request.get("SERVER_NAME"), ["example.zulipchat.com"])
|
||||
self.assert_in_success_response(
|
||||
['href="http://example.zulipchat.com/" id="deactivated-org-auto-redirect"'], result
|
||||
)
|
||||
|
||||
def test_deactivation_notice_when_realm_subdomain_is_changed(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
do_change_realm_subdomain(realm, "new-subdomain-name", acting_user=None)
|
||||
|
||||
result = self.client_get("/login/", follow=True)
|
||||
self.assertIn(result.request.get("SERVER_NAME"), ["new-subdomain-name.testserver"])
|
||||
self.assert_in_success_response(
|
||||
['href="http://new-subdomain-name.testserver/" id="deactivated-org-auto-redirect"'],
|
||||
result,
|
||||
)
|
||||
|
||||
def test_no_deactivation_notice_with_no_redirect(self) -> None:
|
||||
realm = get_realm("zulip")
|
||||
@@ -220,12 +225,16 @@ class DeactivationNoticeTestCase(ZulipTestCase):
|
||||
do_change_realm_subdomain(realm, "new-name-1", acting_user=None)
|
||||
|
||||
result = self.client_get("/login/", follow=True)
|
||||
self.assertIn(result.request.get("SERVER_NAME"), ["new-name-1.testserver"])
|
||||
self.assert_in_success_response(
|
||||
['href="http://new-name-1.testserver/" id="deactivated-org-auto-redirect"'], result
|
||||
)
|
||||
|
||||
realm = get_realm("new-name-1")
|
||||
do_change_realm_subdomain(realm, "new-name-2", acting_user=None)
|
||||
result = self.client_get("/login/", follow=True)
|
||||
self.assertIn(result.request.get("SERVER_NAME"), ["new-name-2.testserver"])
|
||||
self.assert_in_success_response(
|
||||
['href="http://new-name-2.testserver/" id="deactivated-org-auto-redirect"'], result
|
||||
)
|
||||
|
||||
def test_deactivation_notice_when_deactivated_and_scrubbed(self) -> None:
|
||||
# We expect system bot messages when scrubbing a realm.
|
||||
|
||||
@@ -3,7 +3,7 @@ import secrets
|
||||
from collections.abc import Callable, Mapping
|
||||
from functools import wraps
|
||||
from typing import TYPE_CHECKING, Any, Concatenate, TypeAlias, cast
|
||||
from urllib.parse import urlencode, urljoin
|
||||
from urllib.parse import urlencode, urljoin, urlsplit
|
||||
|
||||
import jwt
|
||||
import orjson
|
||||
@@ -63,7 +63,11 @@ from zerver.lib.realm_icon import realm_icon_url
|
||||
from zerver.lib.request import RequestNotes
|
||||
from zerver.lib.response import json_success
|
||||
from zerver.lib.sessions import set_expirable_session_var
|
||||
from zerver.lib.subdomains import get_subdomain, is_subdomain_root_or_alias
|
||||
from zerver.lib.subdomains import (
|
||||
get_subdomain,
|
||||
get_subdomain_from_hostname,
|
||||
is_subdomain_root_or_alias,
|
||||
)
|
||||
from zerver.lib.typed_endpoint import typed_endpoint
|
||||
from zerver.lib.url_encoding import append_url_query_string
|
||||
from zerver.lib.user_agent import parse_user_agent
|
||||
@@ -820,16 +824,21 @@ def redirect_to_misconfigured_ldap_notice(request: HttpRequest, error_type: int)
|
||||
def show_deactivation_notice(request: HttpRequest, next: str = "/") -> HttpResponse:
|
||||
realm = get_realm_from_request(request)
|
||||
if realm and realm.deactivated:
|
||||
if realm.deactivated_redirect is not None:
|
||||
# URL hash is automatically preserved by the browser.
|
||||
# See https://stackoverflow.com/a/5283739
|
||||
redirect_to = get_safe_redirect_to(next, realm.deactivated_redirect)
|
||||
return HttpResponseRedirect(redirect_to)
|
||||
|
||||
realm_data_scrubbed = RealmAuditLog.objects.filter(
|
||||
realm=realm, event_type=AuditLogEventType.REALM_SCRUBBED
|
||||
).exists()
|
||||
context = {"realm_data_deleted": realm_data_scrubbed}
|
||||
context = {
|
||||
"realm_data_deleted": realm_data_scrubbed,
|
||||
"deactivated_redirect": realm.deactivated_redirect,
|
||||
}
|
||||
|
||||
if realm.deactivated_redirect is not None:
|
||||
split = urlsplit(realm.deactivated_redirect)
|
||||
host = f"{split.scheme}://{split.netloc}"
|
||||
# If the redirect is in the same domain, do an automatic redirect.
|
||||
if get_subdomain_from_hostname(host) is not None:
|
||||
redirect_to = get_safe_redirect_to(next, realm.deactivated_redirect)
|
||||
context["auto_redirect_to"] = redirect_to
|
||||
return render(request, "zerver/deactivated.html", context=context)
|
||||
|
||||
return HttpResponseRedirect(reverse("login_page"))
|
||||
|
||||
Reference in New Issue
Block a user