Просмотр исходного кода

fix(hybrid-cloud): Redirect customer domain to last active org (#37788)

Alberto Leal 2 лет назад
Родитель
Сommit
17ddf4c70d
2 измененных файлов с 101 добавлено и 15 удалено
  1. 50 14
      src/sentry/middleware/customer_domain.py
  2. 51 1
      tests/sentry/middleware/test_customer_domain.py

+ 50 - 14
src/sentry/middleware/customer_domain.py

@@ -8,10 +8,54 @@ from rest_framework.request import Request
 from rest_framework.response import Response
 from rest_framework.response import Response
 
 
 from sentry.api.base import resolve_region
 from sentry.api.base import resolve_region
+from sentry.api.utils import generate_organization_url
 from sentry.models import Organization
 from sentry.models import Organization
 from sentry.utils import auth
 from sentry.utils import auth
 
 
 
 
+def _org_exists(slug):
+    if not slug:
+        return False
+    try:
+        Organization.objects.get_from_cache(slug=slug)
+        return True
+    except Organization.DoesNotExist:
+        return False
+
+
+def _resolve_activeorg(request):
+    subdomain = request.subdomain
+    session = getattr(request, "session", None)
+    if _org_exists(subdomain):
+        # Assume subdomain is an org slug being accessed
+        return subdomain
+    elif session and "activeorg" in session and _org_exists(session["activeorg"]):
+        return session["activeorg"]
+    return None
+
+
+def _resolve_redirect_url(request, activeorg):
+    subdomain = request.subdomain
+    redirect_subdomain = subdomain != activeorg
+    redirect_url = ""
+    if redirect_subdomain:
+        redirect_url = generate_organization_url(activeorg)
+    result = resolve(request.path)
+    org_slug_path_mismatch = (
+        result.kwargs
+        and "organization_slug" in result.kwargs
+        and result.kwargs["organization_slug"] != activeorg
+    )
+    if not redirect_subdomain and not org_slug_path_mismatch:
+        return None
+    kwargs = {**result.kwargs}
+    if org_slug_path_mismatch:
+        kwargs["organization_slug"] = activeorg
+    path = reverse(result.url_name, kwargs=kwargs)
+    redirect_url = f"{redirect_url}{path}"
+    return redirect_url
+
+
 class CustomerDomainMiddleware:
 class CustomerDomainMiddleware:
     """
     """
     Set active organization from request.domain.
     Set active organization from request.domain.
@@ -26,22 +70,14 @@ class CustomerDomainMiddleware:
         subdomain = request.subdomain
         subdomain = request.subdomain
         if subdomain is None or resolve_region(request) is not None:
         if subdomain is None or resolve_region(request) is not None:
             return self.get_response(request)
             return self.get_response(request)
-        try:
-            # Assume subdomain is an org slug being accessed
-            Organization.objects.get_from_cache(slug=subdomain)
-        except Organization.DoesNotExist:
+        activeorg = _resolve_activeorg(request)
+        if not activeorg:
             session = getattr(request, "session", None)
             session = getattr(request, "session", None)
             if session and "activeorg" in session:
             if session and "activeorg" in session:
                 del session["activeorg"]
                 del session["activeorg"]
             return self.get_response(request)
             return self.get_response(request)
-        auth.set_active_org(request, subdomain)
-        result = resolve(request.path)
-        if (
-            result.kwargs
-            and "organization_slug" in result.kwargs
-            and result.kwargs["organization_slug"] != subdomain
-        ):
-            return HttpResponseRedirect(
-                reverse(result.url_name, kwargs={**result.kwargs, "organization_slug": subdomain})
-            )
+        auth.set_active_org(request, activeorg)
+        redirect_url = _resolve_redirect_url(request, activeorg)
+        if redirect_url is not None and len(redirect_url) > 0:
+            return HttpResponseRedirect(redirect_url)
         return self.get_response(request)
         return self.get_response(request)

+ 51 - 1
tests/sentry/middleware/test_customer_domain.py

@@ -1,3 +1,5 @@
+from urllib.parse import urlparse
+
 from django.conf import settings
 from django.conf import settings
 from django.conf.urls import url
 from django.conf.urls import url
 from django.test import RequestFactory, override_settings
 from django.test import RequestFactory, override_settings
@@ -22,6 +24,30 @@ class CustomerDomainMiddlewareTest(TestCase):
         assert request.session == {"activeorg": "test"}
         assert request.session == {"activeorg": "test"}
         assert response == request
         assert response == request
 
 
+    def test_recycles_last_active_org(self):
+        self.create_organization(name="test")
+
+        request = RequestFactory().get("/organizations/test/issues/")
+        request.subdomain = "does-not-exist"
+        request.session = {"activeorg": "test"}
+        response = CustomerDomainMiddleware(lambda request: request)(request)
+
+        assert request.session == {"activeorg": "test"}
+        assert response.status_code == 302
+        assert response["Location"] == "http://test.testserver/organizations/test/issues/"
+
+    def test_recycles_last_active_org_path_mismatch(self):
+        self.create_organization(name="test")
+
+        request = RequestFactory().get("/organizations/albertos-apples/issues/")
+        request.subdomain = "does-not-exist"
+        request.session = {"activeorg": "test"}
+        response = CustomerDomainMiddleware(lambda request: request)(request)
+
+        assert request.session == {"activeorg": "test"}
+        assert response.status_code == 302
+        assert response["Location"] == "http://test.testserver/organizations/test/issues/"
+
     def test_removes_active_organization(self):
     def test_removes_active_organization(self):
         request = RequestFactory().get("/")
         request = RequestFactory().get("/")
         request.subdomain = "does-not-exist"
         request.subdomain = "does-not-exist"
@@ -216,7 +242,7 @@ class End2EndTest(APITestCase):
             assert "activeorg" in self.client.session
             assert "activeorg" in self.client.session
             assert self.client.session["activeorg"] == "albertos-apples"
             assert self.client.session["activeorg"] == "albertos-apples"
 
 
-            # Redirect response
+            # Redirect response for org slug path mismatch
             response = self.client.get(
             response = self.client.get(
                 reverse("org-events-endpoint", kwargs={"organization_slug": "some-org"}),
                 reverse("org-events-endpoint", kwargs={"organization_slug": "some-org"}),
                 HTTP_HOST="albertos-apples.testserver",
                 HTTP_HOST="albertos-apples.testserver",
@@ -232,6 +258,30 @@ class End2EndTest(APITestCase):
             assert "activeorg" in self.client.session
             assert "activeorg" in self.client.session
             assert self.client.session["activeorg"] == "albertos-apples"
             assert self.client.session["activeorg"] == "albertos-apples"
 
 
+            # Redirect response for subdomain and path mismatch
+            response = self.client.get(
+                reverse("org-events-endpoint", kwargs={"organization_slug": "some-org"}),
+                HTTP_HOST="does-not-exist.testserver",
+            )
+            assert response.status_code == 302
+            assert (
+                response["Location"] == "http://albertos-apples.testserver/api/0/albertos-apples/"
+            )
+
+            parsed = urlparse(response["Location"])
+            response = self.client.get(
+                parsed.path,
+                HTTP_HOST=parsed.netloc,
+            )
+            assert response.status_code == 200
+            assert response.data == {
+                "organization_slug": "albertos-apples",
+                "subdomain": "albertos-apples",
+                "activeorg": "albertos-apples",
+            }
+            assert "activeorg" in self.client.session
+            assert self.client.session["activeorg"] == "albertos-apples"
+
     def test_without_middleware(self):
     def test_without_middleware(self):
         self.create_organization(name="albertos-apples")
         self.create_organization(name="albertos-apples")