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)
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)
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
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()))
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)
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
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()))
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)
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)
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()))