Example #1
0
def login_or_register_remote_user(
        request: HttpRequest,
        remote_username: Optional[str],
        user_profile: Optional[UserProfile],
        full_name: str = '',
        invalid_subdomain: bool = False,
        mobile_flow_otp: Optional[str] = None,
        is_signup: bool = False,
        redirect_to: str = '',
        multiuse_object_key: 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, 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,
            multiuse_object_key=multiuse_object_key)

    # Otherwise, the user has successfully authenticated to an
    # account, and we need to do the right thing depending whether
    # or not they're using the mobile OTP flow or want a browser session.
    if mobile_flow_otp is not None:
        # For the mobile Oauth flow, we send the API key and other
        # necessary details in a redirect to a zulip:// URI scheme.
        api_key = get_api_key(user_profile)
        params = {
            'otp_encrypted_api_key':
            otp_encrypt_api_key(api_key, mobile_flow_otp),
            'email': email,
            'realm': user_profile.realm.uri,
        }
        # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
        response = HttpResponse(status=302)
        response['Location'] = 'zulip://login?' + urllib.parse.urlencode(
            params)
        # Maybe sending 'user_logged_in' signal is the better approach:
        #   user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile)
        # Not doing this only because over here we don't add the user information
        # in the session. If the signal receiver assumes that we do then that
        # would cause problems.
        email_on_new_login(sender=user_profile.__class__,
                           request=request,
                           user=user_profile)

        # Mark this request as having a logged-in user for our server logs.
        process_client(request, user_profile)
        request._email = user_profile.email

        return response

    do_login(request, user_profile)

    redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri)
    return HttpResponseRedirect(redirect_to)
Example #2
0
def login_or_register_remote_user(request: HttpRequest, remote_username: Optional[Text],
                                  user_profile: Optional[UserProfile], full_name: Text='',
                                  invalid_subdomain: bool=False, mobile_flow_otp: Optional[str]=None,
                                  is_signup: bool=False) -> HttpResponse:
    if user_profile is None or user_profile.is_mirror_dummy:
        # Since execution has reached here, we have verified the user
        # controls an email address (remote_username) but there's no
        # associated Zulip user account.
        if is_signup:
            # If they're trying to sign up, send them over to the PreregistrationUser flow.
            return maybe_send_to_registration(request, remote_user_to_email(remote_username),
                                              full_name, password_required=False)

        # Otherwise, we send them to a special page that asks if they
        # want to register or provided the wrong email and want to go back.
        try:
            validate_email(remote_username)
            invalid_email = False
        except ValidationError:
            # If email address is invalid, we can't send the user
            # PreregistrationUser flow.
            invalid_email = True
        context = {'full_name': full_name,
                   'email': remote_username,
                   'invalid_email': invalid_email}
        return render(request,
                      'zerver/confirm_continue_registration.html',
                      context=context)

    if invalid_subdomain:
        # Show login page with an error message
        return redirect_to_subdomain_login_url()

    if mobile_flow_otp is not None:
        # For the mobile Oauth flow, we send the API key and other
        # necessary details in a redirect to a zulip:// URI scheme.
        params = {
            'otp_encrypted_api_key': otp_encrypt_api_key(user_profile, mobile_flow_otp),
            'email': remote_username,
            'realm': user_profile.realm.uri,
        }
        # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
        response = HttpResponse(status=302)
        response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params)
        # Maybe sending 'user_logged_in' signal is the better approach:
        #   user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile)
        # Not doing this only because over here we don't add the user information
        # in the session. If the signal receiver assumes that we do then that
        # would cause problems.
        email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile)

        # Mark this request as having a logged-in user for our server logs.
        process_client(request, user_profile)
        request._email = user_profile.email

        return response

    do_login(request, user_profile)
    return HttpResponseRedirect(user_profile.realm.uri)
Example #3
0
def login_or_register_remote_user(request: HttpRequest, remote_username: Optional[Text],
                                  user_profile: Optional[UserProfile], full_name: Text='',
                                  invalid_subdomain: bool=False, mobile_flow_otp: Optional[str]=None,
                                  is_signup: bool=False) -> HttpResponse:
    if user_profile is None or user_profile.is_mirror_dummy:
        # Since execution has reached here, we have verified the user
        # controls an email address (remote_username) but there's no
        # associated Zulip user account.
        if is_signup:
            # If they're trying to sign up, send them over to the PreregistrationUser flow.
            return maybe_send_to_registration(request, remote_user_to_email(remote_username),
                                              full_name, password_required=False)

        # Otherwise, we send them to a special page that asks if they
        # want to register or provided the wrong email and want to go back.
        try:
            validate_email(remote_username)
            invalid_email = False
        except ValidationError:
            # If email address is invalid, we can't send the user
            # PreregistrationUser flow.
            invalid_email = True
        context = {'full_name': full_name,
                   'email': remote_username,
                   'invalid_email': invalid_email}
        return render(request,
                      'zerver/confirm_continue_registration.html',
                      context=context)

    if invalid_subdomain:
        # Show login page with an error message
        return redirect_to_subdomain_login_url()

    if mobile_flow_otp is not None:
        # For the mobile Oauth flow, we send the API key and other
        # necessary details in a redirect to a zulip:// URI scheme.
        params = {
            'otp_encrypted_api_key': otp_encrypt_api_key(user_profile, mobile_flow_otp),
            'email': remote_username,
            'realm': user_profile.realm.uri,
        }
        # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
        response = HttpResponse(status=302)
        response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params)
        # Maybe sending 'user_logged_in' signal is the better approach:
        #   user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile)
        # Not doing this only because over here we don't add the user information
        # in the session. If the signal receiver assumes that we do then that
        # would cause problems.
        email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile)

        # Mark this request as having a logged-in user for our server logs.
        process_client(request, user_profile)
        request._email = user_profile.email

        return response

    do_login(request, user_profile)
    return HttpResponseRedirect(user_profile.realm.uri)
Example #4
0
File: auth.py Project: zfeed/zulip
def create_response_for_otp_flow(key: str, otp: str, user_profile: UserProfile) -> HttpResponse:
    params = {
        'otp_encrypted_api_key': otp_encrypt_api_key(key, otp),
        'email': user_profile.delivery_email,
        'realm': user_profile.realm.uri,
    }
    # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
    response = HttpResponse(status=302)
    response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params)

    return response
Example #5
0
def login_or_register_remote_user(request, remote_username, user_profile, full_name='',
                                  invalid_subdomain=False, mobile_flow_otp=None,
                                  is_signup=False):
    # type: (HttpRequest, Text, UserProfile, Text, bool, Optional[str], bool) -> HttpResponse
    if invalid_subdomain:
        # Show login page with an error message
        return redirect_to_subdomain_login_url()

    if user_profile is None or user_profile.is_mirror_dummy:
        # Since execution has reached here, we have verified the user
        # controls an email address (remote_username) but there's no
        # associated Zulip user account.
        if is_signup:
            # If they're trying to sign up, send them over to the PreregistrationUser flow.
            return maybe_send_to_registration(request, remote_user_to_email(remote_username), full_name)

        # Otherwise, we send them to a special page that asks if they
        # want to register or provided the wrong email and want to go back.
        try:
            validate_email(remote_username)
            invalid_email = False
        except ValidationError:
            # If email address is invalid, we can't send the user
            # PreregistrationUser flow.
            invalid_email = True
        context = {'full_name': full_name,
                   'email': remote_username,
                   'invalid_email': invalid_email}
        return render(request,
                      'zerver/confirm_continue_registration.html',
                      context=context)

    if mobile_flow_otp is not None:
        # For the mobile Oauth flow, we send the API key and other
        # necessary details in a redirect to a zulip:// URI scheme.
        params = {
            'otp_encrypted_api_key': otp_encrypt_api_key(user_profile, mobile_flow_otp),
            'email': remote_username,
            'realm': user_profile.realm.uri,
        }
        # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
        response = HttpResponse(status=302)
        response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params)
        return response

    login(request, user_profile)
    if settings.REALMS_HAVE_SUBDOMAINS and user_profile.realm.subdomain is not None:
        return HttpResponseRedirect(user_profile.realm.uri)
    return HttpResponseRedirect("%s%s" % (settings.EXTERNAL_URI_SCHEME,
                                          request.get_host()))
Example #6
0
def login_or_register_remote_user(request: HttpRequest, remote_username: Optional[str],
                                  user_profile: Optional[UserProfile], full_name: str='',
                                  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, 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
    # account, and we need to do the right thing depending whether
    # or not they're using the mobile OTP flow or want a browser session.
    if mobile_flow_otp is not None:
        # For the mobile Oauth flow, we send the API key and other
        # necessary details in a redirect to a zulip:// URI scheme.
        api_key = get_api_key(user_profile)
        params = {
            'otp_encrypted_api_key': otp_encrypt_api_key(api_key, mobile_flow_otp),
            'email': email,
            'realm': user_profile.realm.uri,
        }
        # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
        response = HttpResponse(status=302)
        response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params)
        # Maybe sending 'user_logged_in' signal is the better approach:
        #   user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile)
        # Not doing this only because over here we don't add the user information
        # in the session. If the signal receiver assumes that we do then that
        # would cause problems.
        email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile)

        # Mark this request as having a logged-in user for our server logs.
        process_client(request, user_profile)
        request._email = user_profile.email

        return response

    do_login(request, user_profile)

    redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri)
    return HttpResponseRedirect(redirect_to)
Example #7
0
def create_response_for_otp_flow(key: str, otp: str, user_profile: UserProfile,
                                 encrypted_key_field_name: str) -> HttpResponse:
    realm_uri = user_profile.realm.uri

    # Check if the mobile URI is overridden in settings, if so, replace it
    # This block should only apply to the mobile flow, so we if add others, this
    # needs to be conditional.
    if realm_uri in settings.REALM_MOBILE_REMAP_URIS:
        realm_uri = settings.REALM_MOBILE_REMAP_URIS[realm_uri]

    params = {
        encrypted_key_field_name: otp_encrypt_api_key(key, otp),
        'email': user_profile.delivery_email,
        'realm': realm_uri,
    }
    # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
    response = HttpResponse(status=302)
    response['Location'] = add_query_to_redirect_url('zulip://login', urllib.parse.urlencode(params))

    return response
Example #8
0
def login_or_register_remote_user(request,
                                  remote_username,
                                  user_profile,
                                  full_name='',
                                  invalid_subdomain=False,
                                  mobile_flow_otp=None):
    # type: (HttpRequest, Text, UserProfile, Text, bool, Optional[str]) -> HttpResponse
    if invalid_subdomain:
        # Show login page with an error message
        return redirect_to_subdomain_login_url()

    elif user_profile is None or user_profile.is_mirror_dummy:
        # Since execution has reached here, the client specified a remote user
        # but no associated user account exists. Send them over to the
        # PreregistrationUser flow.
        return maybe_send_to_registration(
            request, remote_user_to_email(remote_username), full_name)
    else:
        # For the mobile Oauth flow, we send the API key and other
        # necessary details in a redirect to a zulip:// URI scheme.
        if mobile_flow_otp is not None:
            params = {
                'otp_encrypted_api_key':
                otp_encrypt_api_key(user_profile, mobile_flow_otp),
                'email':
                remote_username,
                'realm':
                user_profile.realm.uri,
            }
            # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
            response = HttpResponse(status=302)
            response['Location'] = 'zulip://login?' + urllib.parse.urlencode(
                params)
            return response

        login(request, user_profile)
        if settings.REALMS_HAVE_SUBDOMAINS and user_profile.realm.subdomain is not None:
            return HttpResponseRedirect(user_profile.realm.uri)
        return HttpResponseRedirect(
            "%s%s" % (settings.EXTERNAL_URI_SCHEME, request.get_host()))
Example #9
0
def login_or_register_remote_user(
        request: HttpRequest,
        remote_username: str,
        user_profile: Optional[UserProfile],
        full_name: str = '',
        mobile_flow_otp: Optional[str] = None,
        is_signup: bool = False,
        redirect_to: str = '',
        multiuse_object_key: str = '') -> HttpResponse:
    """Given a successful authentication showing the user controls given
    email address (remote_username) and potentially a UserProfile
    object (if the user already has a Zulip account), redirect the
    browser to the appropriate place:

    * The logged-in app if the user already has a Zulip account and is
      trying to login, potentially to an initial narrow or page that had been
      saved in the `redirect_to` parameter.
    * The registration form if is_signup was set (i.e. the user is
      trying to create a Zulip account)
    * A special `confirm_continue_registration.html` "do you want to
      register or try another account" if the user doesn't have a
      Zulip account but is_signup is False (i.e. the user tried to login
      and then did social authentication selecting an email address that does
      not have a Zulip account in this organization).
    * A zulip:// URL to send control back to the mobile apps if they
      are doing authentication using the mobile_flow_otp flow.
    """
    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, 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,
            multiuse_object_key=multiuse_object_key)

    # Otherwise, the user has successfully authenticated to an
    # account, and we need to do the right thing depending whether
    # or not they're using the mobile OTP flow or want a browser session.
    if mobile_flow_otp is not None:
        # For the mobile Oauth flow, we send the API key and other
        # necessary details in a redirect to a zulip:// URI scheme.
        api_key = get_api_key(user_profile)
        params = {
            'otp_encrypted_api_key':
            otp_encrypt_api_key(api_key, mobile_flow_otp),
            'email': email,
            'realm': user_profile.realm.uri,
        }
        # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
        response = HttpResponse(status=302)
        response['Location'] = 'zulip://login?' + urllib.parse.urlencode(
            params)

        # Since we are returning an API key instead of going through
        # the Django login() function (which creates a browser
        # session, etc.), the "new login" signal handler (which
        # triggers an email notification new logins) will not run
        # automatically.  So we call it manually here.
        #
        # Arguably, sending a fake 'user_logged_in' signal would be a better approach:
        #   user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile)
        email_on_new_login(sender=user_profile.__class__,
                           request=request,
                           user=user_profile)

        # Mark this request as having a logged-in user for our server logs.
        process_client(request, user_profile)
        request._email = user_profile.email

        return response

    do_login(request, user_profile)

    redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri)
    return HttpResponseRedirect(redirect_to)
Example #10
0
File: auth.py Project: deltay/zulip
def login_or_register_remote_user(request: HttpRequest, remote_username: Optional[str],
                                  user_profile: Optional[UserProfile], full_name: str='',
                                  invalid_subdomain: bool=False, mobile_flow_otp: Optional[str]=None,
                                  is_signup: bool=False, redirect_to: str='',
                                  multiuse_object_key: str='') -> HttpResponse:
    """Given a successful authentication showing the user controls given
    email address (remote_username) and potentially a UserProfile
    object (if the user already has a Zulip account), redirect the
    browser to the appropriate place:

    * The logged-in app if the user already has a Zulip account and is
      trying to login, potentially to an initial narrow or page that had been
      saved in the `redirect_to` parameter.
    * The registration form if is_signup was set (i.e. the user is
      trying to create a Zulip account)
    * A special `confirm_continue_registration.html` "do you want to
      register or try another account" if the user doesn't have a
      Zulip account but is_signup is False (i.e. the user tried to login
      and then did social authentication selecting an email address that does
      not have a Zulip account in this organization).
    * A zulip:// URL to send control back to the mobile apps if they
      are doing authentication using the mobile_flow_otp flow.
    """
    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, 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, multiuse_object_key=multiuse_object_key)

    # Otherwise, the user has successfully authenticated to an
    # account, and we need to do the right thing depending whether
    # or not they're using the mobile OTP flow or want a browser session.
    if mobile_flow_otp is not None:
        # For the mobile Oauth flow, we send the API key and other
        # necessary details in a redirect to a zulip:// URI scheme.
        api_key = get_api_key(user_profile)
        params = {
            'otp_encrypted_api_key': otp_encrypt_api_key(api_key, mobile_flow_otp),
            'email': email,
            'realm': user_profile.realm.uri,
        }
        # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
        response = HttpResponse(status=302)
        response['Location'] = 'zulip://login?' + urllib.parse.urlencode(params)

        # Since we are returning an API key instead of going through
        # the Django login() function (which creates a browser
        # session, etc.), the "new login" signal handler (which
        # triggers an email notification new logins) will not run
        # automatically.  So we call it manually here.
        #
        # Arguably, sending a fake 'user_logged_in' signal would be a better approach:
        #   user_logged_in.send(sender=user_profile.__class__, request=request, user=user_profile)
        email_on_new_login(sender=user_profile.__class__, request=request, user=user_profile)

        # Mark this request as having a logged-in user for our server logs.
        process_client(request, user_profile)
        request._email = user_profile.email

        return response

    do_login(request, user_profile)

    redirect_to = get_safe_redirect_to(redirect_to, user_profile.realm.uri)
    return HttpResponseRedirect(redirect_to)
Example #11
0
def login_or_register_remote_user(request,
                                  remote_username,
                                  user_profile,
                                  full_name='',
                                  invalid_subdomain=False,
                                  mobile_flow_otp=None,
                                  is_signup=False):
    # type: (HttpRequest, Text, Optional[UserProfile], Text, bool, Optional[str], bool) -> HttpResponse
    if invalid_subdomain:
        # Show login page with an error message
        return redirect_to_subdomain_login_url()

    if user_profile is None or user_profile.is_mirror_dummy:
        # Since execution has reached here, we have verified the user
        # controls an email address (remote_username) but there's no
        # associated Zulip user account.
        if is_signup:
            # If they're trying to sign up, send them over to the PreregistrationUser flow.
            return maybe_send_to_registration(
                request, remote_user_to_email(remote_username), full_name)

        # Otherwise, we send them to a special page that asks if they
        # want to register or provided the wrong email and want to go back.
        try:
            validate_email(remote_username)
            invalid_email = False
        except ValidationError:
            # If email address is invalid, we can't send the user
            # PreregistrationUser flow.
            invalid_email = True
        context = {
            'full_name': full_name,
            'email': remote_username,
            'invalid_email': invalid_email
        }
        return render(request,
                      'zerver/confirm_continue_registration.html',
                      context=context)

    if mobile_flow_otp is not None:
        # For the mobile Oauth flow, we send the API key and other
        # necessary details in a redirect to a zulip:// URI scheme.
        params = {
            'otp_encrypted_api_key':
            otp_encrypt_api_key(user_profile, mobile_flow_otp),
            'email':
            remote_username,
            'realm':
            user_profile.realm.uri,
        }
        # We can't use HttpResponseRedirect, since it only allows HTTP(S) URLs
        response = HttpResponse(status=302)
        response['Location'] = 'zulip://login?' + urllib.parse.urlencode(
            params)
        return response

    login(request, user_profile)
    if settings.REALMS_HAVE_SUBDOMAINS and user_profile.realm.subdomain is not None:
        return HttpResponseRedirect(user_profile.realm.uri)
    return HttpResponseRedirect(
        "%s%s" % (settings.EXTERNAL_URI_SCHEME, request.get_host()))