Example #1
0
 def test_set_and_get_with_delete(self) -> None:
     set_expirable_session_var(
         self.session, "test_set_and_get_with_delete", "some_value", expiry_seconds=10
     )
     value = get_expirable_session_var(self.session, "test_set_and_get_with_delete", delete=True)
     self.assertEqual(value, "some_value")
     self.assertEqual(
         get_expirable_session_var(self.session, "test_set_and_get_with_delete"), None
     )
Example #2
0
 def test_set_and_get_basic(self) -> None:
     start_time = timezone_now()
     with mock.patch('zerver.lib.sessions.timezone_now', return_value=start_time):
         set_expirable_session_var(self.session, 'test_set_and_get_basic', 'some_value', expiry_seconds=10)
         value = get_expirable_session_var(self.session, 'test_set_and_get_basic')
         self.assertEqual(value, 'some_value')
     with mock.patch('zerver.lib.sessions.timezone_now', return_value=start_time + timedelta(seconds=11)):
         value = get_expirable_session_var(self.session, 'test_set_and_get_basic')
         self.assertEqual(value, None)
Example #3
0
def maybe_send_to_registration(
    request: HttpRequest,
    email: str,
    full_name: str = "",
    mobile_flow_otp: Optional[str] = None,
    desktop_flow_otp: Optional[str] = None,
    is_signup: bool = False,
    password_required: bool = True,
    multiuse_object_key: str = "",
    full_name_validated: bool = False,
) -> HttpResponse:
    """Given a successful authentication for an email address (i.e. we've
    confirmed the user controls the email address) that does not
    currently have a Zulip account in the target realm, send them to
    the registration flow or the "continue to registration" flow,
    depending on is_signup, whether the email address can join the
    organization (checked in HomepageForm), and similar details.
    """

    # In the desktop and mobile registration flows, the sign up
    # happens in the browser so the user can use their
    # already-logged-in social accounts.  Then at the end, with the
    # user account created, we pass the appropriate data to the app
    # via e.g. a `zulip://` redirect.  We store the OTP keys for the
    # mobile/desktop flow in the session with 1-hour expiry, because
    # we want this configuration of having a successful authentication
    # result in being logged into the app to persist if the user makes
    # mistakes while trying to authenticate (E.g. clicks the wrong
    # Google account, hits back, etc.) during a given browser session,
    # rather than just logging into the webapp in the target browser.
    #
    # We can't use our usual pre-account-creation state storage
    # approach of putting something in PreregistrationUser, because
    # that would apply to future registration attempts on other
    # devices, e.g. just creating an account on the web on their laptop.
    assert not (mobile_flow_otp and desktop_flow_otp)
    if mobile_flow_otp:
        set_expirable_session_var(
            request.session, "registration_mobile_flow_otp", mobile_flow_otp, expiry_seconds=3600
        )
    elif desktop_flow_otp:
        set_expirable_session_var(
            request.session, "registration_desktop_flow_otp", desktop_flow_otp, expiry_seconds=3600
        )

    if multiuse_object_key:
        from_multiuse_invite = True
        multiuse_obj = Confirmation.objects.get(confirmation_key=multiuse_object_key).content_object
        realm = multiuse_obj.realm
        invited_as = multiuse_obj.invited_as
    else:
        from_multiuse_invite = False
        multiuse_obj = None
        try:
            realm = get_realm(get_subdomain(request))
        except Realm.DoesNotExist:
            realm = None
        invited_as = PreregistrationUser.INVITE_AS["MEMBER"]

    form = HomepageForm({"email": email}, realm=realm, from_multiuse_invite=from_multiuse_invite)
    if form.is_valid():
        # If the email address is allowed to sign up for an account in
        # this organization, construct a PreregistrationUser and
        # Confirmation objects, and then send the user to account
        # creation or confirm-continue-registration depending on
        # is_signup.
        try:
            prereg_user = filter_to_valid_prereg_users(
                PreregistrationUser.objects.filter(email__iexact=email, realm=realm)
            ).latest("invited_at")

            # password_required and full_name data passed here as argument should take precedence
            # over the defaults with which the existing PreregistrationUser that we've just fetched
            # was created.
            prereg_user.password_required = password_required
            update_fields = ["password_required"]
            if full_name:
                prereg_user.full_name = full_name
                prereg_user.full_name_validated = full_name_validated
                update_fields.extend(["full_name", "full_name_validated"])
            prereg_user.save(update_fields=update_fields)
        except PreregistrationUser.DoesNotExist:
            prereg_user = create_preregistration_user(
                email,
                request,
                password_required=password_required,
                full_name=full_name,
                full_name_validated=full_name_validated,
            )

        if multiuse_obj is not None:
            request.session.modified = True
            streams_to_subscribe = list(multiuse_obj.streams.all())
            prereg_user.streams.set(streams_to_subscribe)
            prereg_user.invited_as = invited_as
            prereg_user.save()

        confirmation_link = create_confirmation_link(prereg_user, Confirmation.USER_REGISTRATION)
        if is_signup:
            return redirect(confirmation_link)

        context = {"email": email, "continue_link": confirmation_link, "full_name": full_name}
        return render(request, "zerver/confirm_continue_registration.html", context=context)

    # This email address it not allowed to join this organization, so
    # just send the user back to the registration page.
    url = reverse("register")
    context = login_context(request)
    extra_context: Mapping[str, Any] = {
        "form": form,
        "current_url": lambda: url,
        "from_multiuse_invite": from_multiuse_invite,
        "multiuse_object_key": multiuse_object_key,
        "mobile_flow_otp": mobile_flow_otp,
        "desktop_flow_otp": desktop_flow_otp,
    }
    context.update(extra_context)
    return render(request, "zerver/accounts_home.html", context=context)
Example #4
0
File: auth.py Project: qnxor/zulip
def maybe_send_to_registration(
        request: HttpRequest,
        email: str,
        full_name: str = '',
        mobile_flow_otp: Optional[str] = None,
        desktop_flow_otp: Optional[str] = None,
        is_signup: bool = False,
        password_required: bool = True,
        multiuse_object_key: str = '',
        full_name_validated: bool = False) -> HttpResponse:
    """Given a successful authentication for an email address (i.e. we've
    confirmed the user controls the email address) that does not
    currently have a Zulip account in the target realm, send them to
    the registration flow or the "continue to registration" flow,
    depending on is_signup, whether the email address can join the
    organization (checked in HomepageForm), and similar details.
    """

    # In the desktop and mobile registration flows, the sign up
    # happens in the browser so the user can use their
    # already-logged-in social accounts.  Then at the end, with the
    # user account created, we pass the appropriate data to the app
    # via e.g. a `zulip://` redirect.  We store the OTP keys for the
    # mobile/desktop flow in the session with 1-hour expiry, because
    # we want this configuration of having a successful authentication
    # result in being logged into the app to persist if the user makes
    # mistakes while trying to authenticate (E.g. clicks the wrong
    # Google account, hits back, etc.) during a given browser session,
    # rather than just logging into the webapp in the target browser.
    #
    # We can't use our usual pre-account-creation state storage
    # approach of putting something in PreregistrationUser, because
    # that would apply to future registration attempts on other
    # devices, e.g. just creating an account on the web on their laptop.
    assert not (mobile_flow_otp and desktop_flow_otp)
    if mobile_flow_otp:
        set_expirable_session_var(request.session,
                                  'registration_mobile_flow_otp',
                                  mobile_flow_otp,
                                  expiry_seconds=3600)
    elif desktop_flow_otp:
        set_expirable_session_var(request.session,
                                  'registration_desktop_flow_otp',
                                  desktop_flow_otp,
                                  expiry_seconds=3600)

    if multiuse_object_key:
        from_multiuse_invite = True
        multiuse_obj = Confirmation.objects.get(
            confirmation_key=multiuse_object_key).content_object
        realm = multiuse_obj.realm
        invited_as = multiuse_obj.invited_as
    else:
        from_multiuse_invite = False
        multiuse_obj = None
        try:
            realm = get_realm(get_subdomain(request))
        except Realm.DoesNotExist:
            realm = None
        invited_as = PreregistrationUser.INVITE_AS['MEMBER']

    form = HomepageForm({'email': email},
                        realm=realm,
                        from_multiuse_invite=from_multiuse_invite)
    if form.is_valid():
        # If the email address is allowed to sign up for an account in
        # this organization, construct a PreregistrationUser and
        # Confirmation objects, and then send the user to account
        # creation or confirm-continue-registration depending on
        # is_signup.
        try:
            prereg_user = PreregistrationUser.objects.filter(
                email__iexact=email, realm=realm).latest("invited_at")

            # password_required and full_name data passed here as argument should take precedence
            # over the defaults with which the existing PreregistrationUser that we've just fetched
            # was created.
            prereg_user.password_required = password_required
            update_fields = ["password_required"]
            if full_name:
                prereg_user.full_name = full_name
                prereg_user.full_name_validated = full_name_validated
                update_fields.extend(["full_name", "full_name_validated"])
            prereg_user.save(update_fields=update_fields)
        except PreregistrationUser.DoesNotExist:
            prereg_user = create_preregistration_user(
                email,
                request,
                password_required=password_required,
                full_name=full_name,
                full_name_validated=full_name_validated,
            )

        if multiuse_obj is not None:
            request.session.modified = True
            streams_to_subscribe = list(multiuse_obj.streams.all())
            prereg_user.streams.set(streams_to_subscribe)
            prereg_user.invited_as = invited_as
            prereg_user.save()

        # We want to create a confirmation link to create an account
        # in the current realm, i.e. one with a hostname of
        # realm.host.  For the Apache REMOTE_USER_SSO auth code path,
        # this is preferable over realm.get_host() because the latter
        # contains the port number of the Apache instance and we want
        # to send the user back to nginx.  But if we're in the realm
        # creation code path, there might not be a realm yet, so we
        # have to use request.get_host().
        if realm is not None:
            host = realm.host
        else:
            host = request.get_host()
        # Mark 'host' as safe for use in a redirect. It's pulled from the
        # current request or realm, both of which only allow a limited set of
        # trusted hosts.
        confirmation_link = create_confirmation_link(
            prereg_user, mark_sanitized(host), Confirmation.USER_REGISTRATION)
        if is_signup:
            return redirect(confirmation_link)

        context = {
            'email': email,
            'continue_link': confirmation_link,
            'full_name': full_name
        }
        return render(request,
                      'zerver/confirm_continue_registration.html',
                      context=context)

    # This email address it not allowed to join this organization, so
    # just send the user back to the registration page.
    url = reverse('register')
    context = login_context(request)
    extra_context: Mapping[str, Any] = {
        'form': form,
        'current_url': lambda: url,
        'from_multiuse_invite': from_multiuse_invite,
        'multiuse_object_key': multiuse_object_key,
        'mobile_flow_otp': mobile_flow_otp,
        'desktop_flow_otp': desktop_flow_otp,
    }
    context.update(extra_context)
    return render(request, 'zerver/accounts_home.html', context=context)