From 3e7fc1778840092b7562bfaacabc88c07cedc9f9 Mon Sep 17 00:00:00 2001 From: Mateusz Mandera Date: Mon, 1 Jun 2020 14:24:21 +0200 Subject: [PATCH] auth: Delegate RemoteUser SSO to browser when using the desktop app. --- zerver/tests/test_auth_backends.py | 14 ++++++++++++++ zerver/views/auth.py | 11 +++++++++++ zproject/backends.py | 4 ++-- zproject/urls.py | 1 + 4 files changed, 28 insertions(+), 2 deletions(-) diff --git a/zerver/tests/test_auth_backends.py b/zerver/tests/test_auth_backends.py index ce5158bc51..12b77dd4ef 100644 --- a/zerver/tests/test_auth_backends.py +++ b/zerver/tests/test_auth_backends.py @@ -3089,6 +3089,20 @@ class TestDevAuthBackend(ZulipTestCase): self.assertRedirects(response, reverse('config_error', kwargs={'error_category_name': 'dev'})) class TestZulipRemoteUserBackend(DesktopFlowTestingLib, ZulipTestCase): + def test_start_remote_user_sso(self) -> None: + result = self.client_get('/accounts/login/start/sso/?param1=value1¶ms=value2') + self.assertEqual(result.status_code, 302) + + url = result.url + parsed_url = urllib.parse.urlparse(url) + self.assertEqual(parsed_url.path, '/accounts/login/sso/') + self.assertEqual(parsed_url.query, 'param1=value1¶ms=value2') + + def test_start_remote_user_sso_with_desktop_app(self) -> None: + headers = dict(HTTP_USER_AGENT="ZulipElectron/5.0.0") + result = self.client_get('/accounts/login/start/sso/', **headers) + self.verify_desktop_flow_app_page(result) + def test_login_success(self) -> None: user_profile = self.example_user('hamlet') email = user_profile.delivery_email diff --git a/zerver/views/auth.py b/zerver/views/auth.py index 21faed1de6..db069af4d7 100644 --- a/zerver/views/auth.py +++ b/zerver/views/auth.py @@ -463,6 +463,17 @@ def handle_desktop_flow(func: ViewFuncT) -> ViewFuncT: return func(request, *args, **kwargs) return wrapper # type: ignore[return-value] # https://github.com/python/mypy/issues/1927 +@handle_desktop_flow +def start_remote_user_sso(request: HttpRequest) -> HttpResponse: + """ + The purpose of this endpoint is to provide an initial step in the flow + on which we can handle the special behavior for the desktop app. + /accounts/login/sso may have Apache intercepting requests to it + to do authentication, so we need this additional endpoint. + """ + query = request.META['QUERY_STRING'] + return redirect(add_query_to_redirect_url(reverse('login-sso'), query)) + @handle_desktop_flow def start_social_login(request: HttpRequest, backend: str, extra_arg: Optional[str]=None ) -> HttpResponse: diff --git a/zproject/backends.py b/zproject/backends.py index d70cbf4a43..3f7de69a9a 100644 --- a/zproject/backends.py +++ b/zproject/backends.py @@ -1035,8 +1035,8 @@ class ZulipRemoteUserBackend(RemoteUserBackend, ExternalAuthMethod): display_name="SSO", display_icon=cls.display_icon, # The user goes to the same URL for both login and signup: - login_url=reverse('login-sso'), - signup_url=reverse('login-sso'), + login_url=reverse('start-login-sso'), + signup_url=reverse('start-login-sso'), )] def redirect_deactivated_user_to_login() -> HttpResponseRedirect: diff --git a/zproject/urls.py b/zproject/urls.py index b258fff78e..e7e7446564 100644 --- a/zproject/urls.py +++ b/zproject/urls.py @@ -426,6 +426,7 @@ i18n_urls = [ url(r'^accounts/login/(google)/$', zerver.views.auth.start_social_login, name='login-social'), + url(r'^accounts/login/start/sso/$', zerver.views.auth.start_remote_user_sso, name='start-login-sso'), url(r'^accounts/login/sso/$', zerver.views.auth.remote_user_sso, name='login-sso'), url(r'^accounts/login/jwt/$', zerver.views.auth.remote_user_jwt, name='login-jwt'), url(r'^accounts/login/social/([\w,-]+)$', zerver.views.auth.start_social_login,