auth: Delegate RemoteUser SSO to browser when using the desktop app.

This commit is contained in:
Mateusz Mandera
2020-06-01 14:24:21 +02:00
committed by Tim Abbott
parent c4d0bd6445
commit 3e7fc17788
4 changed files with 28 additions and 2 deletions

View File

@@ -3089,6 +3089,20 @@ class TestDevAuthBackend(ZulipTestCase):
self.assertRedirects(response, reverse('config_error', kwargs={'error_category_name': 'dev'})) self.assertRedirects(response, reverse('config_error', kwargs={'error_category_name': 'dev'}))
class TestZulipRemoteUserBackend(DesktopFlowTestingLib, ZulipTestCase): class TestZulipRemoteUserBackend(DesktopFlowTestingLib, ZulipTestCase):
def test_start_remote_user_sso(self) -> None:
result = self.client_get('/accounts/login/start/sso/?param1=value1&params=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&params=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: def test_login_success(self) -> None:
user_profile = self.example_user('hamlet') user_profile = self.example_user('hamlet')
email = user_profile.delivery_email email = user_profile.delivery_email

View File

@@ -463,6 +463,17 @@ def handle_desktop_flow(func: ViewFuncT) -> ViewFuncT:
return func(request, *args, **kwargs) return func(request, *args, **kwargs)
return wrapper # type: ignore[return-value] # https://github.com/python/mypy/issues/1927 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 @handle_desktop_flow
def start_social_login(request: HttpRequest, backend: str, extra_arg: Optional[str]=None def start_social_login(request: HttpRequest, backend: str, extra_arg: Optional[str]=None
) -> HttpResponse: ) -> HttpResponse:

View File

@@ -1035,8 +1035,8 @@ class ZulipRemoteUserBackend(RemoteUserBackend, ExternalAuthMethod):
display_name="SSO", display_name="SSO",
display_icon=cls.display_icon, display_icon=cls.display_icon,
# The user goes to the same URL for both login and signup: # The user goes to the same URL for both login and signup:
login_url=reverse('login-sso'), login_url=reverse('start-login-sso'),
signup_url=reverse('login-sso'), signup_url=reverse('start-login-sso'),
)] )]
def redirect_deactivated_user_to_login() -> HttpResponseRedirect: def redirect_deactivated_user_to_login() -> HttpResponseRedirect:

View File

@@ -426,6 +426,7 @@ i18n_urls = [
url(r'^accounts/login/(google)/$', zerver.views.auth.start_social_login, url(r'^accounts/login/(google)/$', zerver.views.auth.start_social_login,
name='login-social'), 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/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/jwt/$', zerver.views.auth.remote_user_jwt, name='login-jwt'),
url(r'^accounts/login/social/([\w,-]+)$', zerver.views.auth.start_social_login, url(r'^accounts/login/social/([\w,-]+)$', zerver.views.auth.start_social_login,