mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 05:53:43 +00:00 
			
		
		
		
	auth: Handle SSO_APPEND_DOMAIN in remote_user SSO for mobile.
Apparently, while the main code path through login_or_register_remote_user was correctly calling remote_user_to_email(username) to get a proper email address for situations where auth username != email (i.e. when SSO_APPEND_DOMAIN is set), we neglected to do so in the mobile_flow_otp corner case. Fixes #11005.
This commit is contained in:
		@@ -1911,7 +1911,7 @@ class TestZulipRemoteUserBackend(ZulipTestCase):
 | 
			
		||||
 | 
			
		||||
    @override_settings(SEND_LOGIN_EMAILS=True)
 | 
			
		||||
    @override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipRemoteUserBackend',))
 | 
			
		||||
    def test_login_mobile_flow_otp_success(self) -> None:
 | 
			
		||||
    def test_login_mobile_flow_otp_success_email(self) -> None:
 | 
			
		||||
        user_profile = self.example_user('hamlet')
 | 
			
		||||
        email = user_profile.email
 | 
			
		||||
        user_profile.date_joined = timezone_now() - datetime.timedelta(seconds=61)
 | 
			
		||||
@@ -1950,6 +1950,49 @@ class TestZulipRemoteUserBackend(ZulipTestCase):
 | 
			
		||||
        self.assertEqual(len(mail.outbox), 1)
 | 
			
		||||
        self.assertIn('Zulip on Android', mail.outbox[0].body)
 | 
			
		||||
 | 
			
		||||
    @override_settings(SEND_LOGIN_EMAILS=True)
 | 
			
		||||
    @override_settings(SSO_APPEND_DOMAIN="zulip.com")
 | 
			
		||||
    @override_settings(AUTHENTICATION_BACKENDS=('zproject.backends.ZulipRemoteUserBackend',))
 | 
			
		||||
    def test_login_mobile_flow_otp_success_username(self) -> None:
 | 
			
		||||
        user_profile = self.example_user('hamlet')
 | 
			
		||||
        email = user_profile.email
 | 
			
		||||
        remote_user = email_to_username(email)
 | 
			
		||||
        user_profile.date_joined = timezone_now() - datetime.timedelta(seconds=61)
 | 
			
		||||
        user_profile.save()
 | 
			
		||||
        mobile_flow_otp = '1234abcd' * 8
 | 
			
		||||
 | 
			
		||||
        # Verify that the right thing happens with an invalid-format OTP
 | 
			
		||||
        result = self.client_post('/accounts/login/sso/',
 | 
			
		||||
                                  dict(mobile_flow_otp="1234"),
 | 
			
		||||
                                  REMOTE_USER=remote_user,
 | 
			
		||||
                                  HTTP_USER_AGENT = "ZulipAndroid")
 | 
			
		||||
        self.assertIs(get_session_dict_user(self.client.session), None)
 | 
			
		||||
        self.assert_json_error_contains(result, "Invalid OTP", 400)
 | 
			
		||||
 | 
			
		||||
        result = self.client_post('/accounts/login/sso/',
 | 
			
		||||
                                  dict(mobile_flow_otp="invalido" * 8),
 | 
			
		||||
                                  REMOTE_USER=remote_user,
 | 
			
		||||
                                  HTTP_USER_AGENT = "ZulipAndroid")
 | 
			
		||||
        self.assertIs(get_session_dict_user(self.client.session), None)
 | 
			
		||||
        self.assert_json_error_contains(result, "Invalid OTP", 400)
 | 
			
		||||
 | 
			
		||||
        result = self.client_post('/accounts/login/sso/',
 | 
			
		||||
                                  dict(mobile_flow_otp=mobile_flow_otp),
 | 
			
		||||
                                  REMOTE_USER=remote_user,
 | 
			
		||||
                                  HTTP_USER_AGENT = "ZulipAndroid")
 | 
			
		||||
        self.assertEqual(result.status_code, 302)
 | 
			
		||||
        redirect_url = result['Location']
 | 
			
		||||
        parsed_url = urllib.parse.urlparse(redirect_url)
 | 
			
		||||
        query_params = urllib.parse.parse_qs(parsed_url.query)
 | 
			
		||||
        self.assertEqual(parsed_url.scheme, 'zulip')
 | 
			
		||||
        self.assertEqual(query_params["realm"], ['http://zulip.testserver'])
 | 
			
		||||
        self.assertEqual(query_params["email"], [self.example_email("hamlet")])
 | 
			
		||||
        encrypted_api_key = query_params["otp_encrypted_api_key"][0]
 | 
			
		||||
        hamlet_api_keys = get_all_api_keys(self.example_user('hamlet'))
 | 
			
		||||
        self.assertIn(otp_decrypt_api_key(encrypted_api_key, mobile_flow_otp), hamlet_api_keys)
 | 
			
		||||
        self.assertEqual(len(mail.outbox), 1)
 | 
			
		||||
        self.assertIn('Zulip on Android', mail.outbox[0].body)
 | 
			
		||||
 | 
			
		||||
    def test_redirect_to(self) -> None:
 | 
			
		||||
        """This test verifies the behavior of the redirect_to logic in
 | 
			
		||||
        login_or_register_remote_user."""
 | 
			
		||||
 
 | 
			
		||||
@@ -142,11 +142,12 @@ def login_or_register_remote_user(request: HttpRequest, remote_username: Optiona
 | 
			
		||||
                                  invalid_subdomain: bool=False, mobile_flow_otp: Optional[str]=None,
 | 
			
		||||
                                  is_signup: bool=False,
 | 
			
		||||
                                  redirect_to: str='') -> HttpResponse:
 | 
			
		||||
    email = remote_user_to_email(remote_username)
 | 
			
		||||
    if user_profile is None or user_profile.is_mirror_dummy:
 | 
			
		||||
        # We have verified the user controls an email address
 | 
			
		||||
        # (remote_username) but there's no associated Zulip user
 | 
			
		||||
        # account.  Consider sending the request to registration.
 | 
			
		||||
        return maybe_send_to_registration(request, remote_user_to_email(remote_username),
 | 
			
		||||
        # We have verified the user controls an email address, but
 | 
			
		||||
        # there's no associated Zulip user account.  Consider sending
 | 
			
		||||
        # the request to registration.
 | 
			
		||||
        return maybe_send_to_registration(request, email,
 | 
			
		||||
                                          full_name, password_required=False, is_signup=is_signup)
 | 
			
		||||
 | 
			
		||||
    # Otherwise, the user has successfully authenticated to an
 | 
			
		||||
@@ -158,7 +159,7 @@ def login_or_register_remote_user(request: HttpRequest, remote_username: Optiona
 | 
			
		||||
        api_key = get_api_key(user_profile)
 | 
			
		||||
        params = {
 | 
			
		||||
            'otp_encrypted_api_key': otp_encrypt_api_key(api_key, mobile_flow_otp),
 | 
			
		||||
            'email': remote_username,
 | 
			
		||||
            'email': email,
 | 
			
		||||
            'realm': user_profile.realm.uri,
 | 
			
		||||
        }
 | 
			
		||||
        # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user