def authenticate(self, remote_user): # type: (str) -> Optional[UserProfile] if not remote_user: return None email = remote_user_to_email(remote_user) return common_get_active_user_by_email(email)
def remote_user_sso(request: HttpRequest, mobile_flow_otp: Optional[str]=REQ(default=None)) -> HttpResponse: try: remote_user = request.META["REMOTE_USER"] except KeyError: # TODO: Arguably the JsonableError values here should be # full-page HTML configuration errors instead. raise JsonableError(_("No REMOTE_USER set.")) # Django invokes authenticate methods by matching arguments, and this # authentication flow will not invoke LDAP authentication because of # this condition of Django so no need to check if LDAP backend is # enabled. validate_login_email(remote_user_to_email(remote_user)) # Here we support the mobile flow for REMOTE_USER_BACKEND; we # validate the data format and then pass it through to # login_or_register_remote_user if appropriate. if mobile_flow_otp is not None: if not is_valid_otp(mobile_flow_otp): raise JsonableError(_("Invalid OTP")) subdomain = get_subdomain(request) realm = get_realm(subdomain) # Since RemoteUserBackend will return None if Realm is None, we # don't need to check whether `get_realm` returned None. user_profile = authenticate(remote_user=remote_user, realm=realm) return login_or_register_remote_user(request, remote_user, user_profile, mobile_flow_otp=mobile_flow_otp)
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 authenticate(self, remote_user: Optional[str], realm: Optional[Realm]=None, return_data: Optional[Dict[str, Any]]=None) -> Optional[UserProfile]: assert remote_user is not None if realm is None: return None if not auth_enabled_helper(["RemoteUser"], realm): return None email = remote_user_to_email(remote_user) return common_get_active_user(email, realm, return_data=return_data)
def authenticate(self, remote_user, realm_subdomain=None): # type: (str, Optional[text_type]) -> Optional[UserProfile] if not remote_user: return None email = remote_user_to_email(remote_user) user = common_get_active_user_by_email(email) if user is not None and check_subdomain(realm_subdomain, user.realm.subdomain): return user return None
def authenticate(self, remote_user, realm_subdomain=None): # type: (str, Optional[Text]) -> Optional[UserProfile] if not remote_user: return None email = remote_user_to_email(remote_user) user_profile = common_get_active_user_by_email(email) if user_profile is None: return None if not check_subdomain(realm_subdomain, user_profile.realm.subdomain): return None if not auth_enabled_helper([u"RemoteUser"], user_profile.realm): return None return user_profile
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 remote_user_sso(request): # type: (HttpRequest) -> HttpResponse try: remote_user = request.META["REMOTE_USER"] except KeyError: raise JsonableError(_("No REMOTE_USER set.")) # Django invokes authenticate methods by matching arguments, and this # authentication flow will not invoke LDAP authentication because of # this condition of Django so no need to check if LDAP backend is # enabled. validate_login_email(remote_user_to_email(remote_user)) user_profile = authenticate(remote_user=remote_user, realm_subdomain=get_subdomain(request)) return login_or_register_remote_user(request, remote_user, user_profile)
def authenticate(self, remote_user): if not remote_user: return email = remote_user_to_email(remote_user) try: user_profile = get_user_profile_by_email(email) except UserProfile.DoesNotExist: return None if user_profile.is_mirror_dummy: # mirror dummies can not login, but they can convert to real users return None return user_profile
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 login_or_register_remote_user(request, remote_username, user_profile, full_name='', invalid_subdomain=False): # type: (HttpRequest, text_type, UserProfile, text_type, Optional[bool]) -> 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: 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 remote_user_sso(request: HttpRequest) -> HttpResponse: try: remote_user = request.META["REMOTE_USER"] except KeyError: raise JsonableError(_("No REMOTE_USER set.")) # Django invokes authenticate methods by matching arguments, and this # authentication flow will not invoke LDAP authentication because of # this condition of Django so no need to check if LDAP backend is # enabled. validate_login_email(remote_user_to_email(remote_user)) subdomain = get_subdomain(request) realm = get_realm(subdomain) # Since RemoteUserBackend will return None if Realm is None, we # don't need to check whether `get_realm` returned None. user_profile = authenticate(remote_user=remote_user, realm=realm) return login_or_register_remote_user(request, remote_user, user_profile)
def authenticate(self, remote_user): if not remote_user: return None email = remote_user_to_email(remote_user) return common_get_active_user_by_email(email)
def login_or_register_remote_user(request: HttpRequest, remote_username: 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, Optional[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, 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 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 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, 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()))