def log_into_subdomain(request: HttpRequest, token: str) -> HttpResponse: """Given a valid authentication token (generated by redirect_and_log_into_subdomain called on auth.zulip.example.com), call login_or_register_remote_user, passing all the authentication result data that has been stored in redis, associated with this token. """ if not has_api_key_format( token ): # The tokens are intended to have the same format as API keys. logging.warning("log_into_subdomain: Malformed token given: %s", token) return HttpResponse(status=400) try: result = ExternalAuthResult(login_token=token) except ExternalAuthResult.InvalidTokenError: logging.warning("log_into_subdomain: Invalid token given: %s", token) return render(request, 'zerver/log_into_subdomain_token_invalid.html', status=400) subdomain = get_subdomain(request) if result.data_dict['subdomain'] != subdomain: raise JsonableError(_("Invalid subdomain")) return login_or_register_remote_user(request, result)
def access_user_by_api_key(request: HttpRequest, api_key: str, email: Optional[str]=None) -> UserProfile: if not has_api_key_format(api_key): raise InvalidAPIKeyFormatError() try: user_profile = get_user_profile_by_api_key(api_key) except UserProfile.DoesNotExist: raise InvalidAPIKeyError() if email is not None and email.lower() != user_profile.delivery_email.lower(): # This covers the case that the API key is correct, but for a # different user. We may end up wanting to relaxing this # constraint or give a different error message in the future. raise InvalidAPIKeyError() validate_account_and_subdomain(request, user_profile) return user_profile
def log_into_subdomain(request: HttpRequest, token: str) -> HttpResponse: """Given a valid authentication token (generated by redirect_and_log_into_subdomain called on auth.zulip.example.com), call login_or_register_remote_user, passing all the authentication result data that has been stored in redis, associated with this token. Obligatory fields for the data are 'subdomain' and 'email', because this endpoint needs to know which user and realm to log into. Others are optional and only used if the user account still needs to be made and they're passed as argument to the register_remote_user function. """ if not has_api_key_format( token ): # The tokens are intended to have the same format as API keys. logging.warning("log_into_subdomain: Malformed token given: %s" % (token, )) return HttpResponse(status=400) data = get_login_data(token) if data is None: logging.warning("log_into_subdomain: Invalid token given: %s" % (token, )) return HttpResponse(status=400) # We extract fields provided by the caller via the data object. # The only fields that are required are email and subdomain (if we # are simply doing login); more fields are expected if this is a # new account registration flow or we're going to a specific # narrow after login. subdomain = get_subdomain(request) if data['subdomain'] != subdomain: raise JsonableError(_("Invalid subdomain")) email_address = data['email'] full_name = data.get('name', '') is_signup = data.get('is_signup', False) redirect_to = data.get('next', '') full_name_validated = data.get('full_name_validated', False) multiuse_object_key = data.get('multiuse_object_key', '') # We cannot pass the actual authenticated user_profile object that # was fetched by the original authentication backend and passed # into redirect_and_log_into_subdomain through a signed URL token, # so we need to re-fetch it from the database. if is_signup: # If we are creating a new user account, user_profile will # always have been None, so we set that here. In the event # that a user account with this email was somehow created in a # race, the eventual registration code will catch that and # throw an error, so we don't need to check for that here. user_profile = None else: # We're just trying to login. We can be reasonably confident # that this subdomain actually has a corresponding active # realm, since the signed cookie proves there was one very # recently. But as part of fetching the UserProfile object # for the target user, we use DummyAuthBackend, which # conveniently re-validates that the realm and user account # were not deactivated in the meantime. # Note: Ideally, we'd have a nice user-facing error message # for the case where this auth fails (because e.g. the realm # or user was deactivated since the signed cookie was # generated < 15 seconds ago), but the authentication result # is correct in those cases and such a race would be very # rare, so a nice error message is low priority. realm = get_realm(subdomain) user_profile = authenticate_remote_user(realm, email_address) return login_or_register_remote_user( request, email_address, user_profile, full_name, is_signup=is_signup, redirect_to=redirect_to, multiuse_object_key=multiuse_object_key, full_name_validated=full_name_validated)