def dispatch_to_register(): """Redirects to the registration page.""" request = strategy.request data = kwargs['response'] data['terms_of_service'] = True data['honor_code'] = True data['password'] = '******' data['name'] = ' '.join([data['firstname'], data['lastname']]) data['provider'] = backend.name if request.session.get('ExternalAuthMap'): del request.session['ExternalAuthMap'] if User.objects.filter(email=data['email']).exists(): return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_LOGIN]) create_account_with_params(request, data) user = request.user user.is_active = True user.save() set_logged_in_cookies(request, JsonResponse({"success": True})) # add roles for User add_user_roles(user, data['permissions']) return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_LOGIN])
def login_user(request): """ AJAX request to log in the user. """ third_party_auth_requested = third_party_auth.is_enabled() and pipeline.running(request) trumped_by_first_party_auth = bool(request.POST.get('email')) or bool(request.POST.get('password')) was_authenticated_third_party = False try: if third_party_auth_requested and not trumped_by_first_party_auth: # The user has already authenticated via third-party auth and has not # asked to do first party auth by supplying a username or password. We # now want to put them through the same logging and cookie calculation # logic as with first-party auth. # This nested try is due to us only returning an HttpResponse in this # one case vs. JsonResponse everywhere else. try: email_user = _do_third_party_auth(request) was_authenticated_third_party = True except AuthFailedError as e: return HttpResponse(e.value, content_type="text/plain", status=403) else: email_user = _get_user_by_email(request) _check_shib_redirect(email_user) _check_excessive_login_attempts(email_user) _check_forced_password_reset(email_user) possibly_authenticated_user = email_user if not was_authenticated_third_party: possibly_authenticated_user = _authenticate_first_party(request, email_user) if possibly_authenticated_user and password_policy_compliance.should_enforce_compliance_on_login(): # Important: This call must be made AFTER the user was successfully authenticated. _enforce_password_policy_compliance(request, possibly_authenticated_user) if possibly_authenticated_user is None or not possibly_authenticated_user.is_active: _handle_failed_authentication(email_user) _handle_successful_authentication_and_login(possibly_authenticated_user, request) redirect_url = None # The AJAX method calling should know the default destination upon success if was_authenticated_third_party: running_pipeline = pipeline.get(request) redirect_url = pipeline.get_complete_url(backend_name=running_pipeline['backend']) response = JsonResponse({ 'success': True, 'redirect_url': redirect_url, }) # Ensure that the external marketing site can # detect that the user is logged in. return set_logged_in_cookies(request, response, possibly_authenticated_user) except AuthFailedError as error: return JsonResponse(error.get_response())
def dispatch_to_register(): """Redirects to the registration page.""" request = strategy.request data = kwargs['response'] data['terms_of_service'] = True data['honor_code'] = True data['password'] = '******' data['name'] = ' '.join([data['firstname'], data['lastname']]) data['provider'] = backend.name if request.session.get('ExternalAuthMap'): del request.session['ExternalAuthMap'] create_account_with_params(request, data) user = request.user user.is_active = True user.save() set_logged_in_cookies(request, JsonResponse({"success": True})) return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_LOGIN])
def post(self, request): """Create the user's account. You must send all required form fields with the request. You can optionally send a "course_id" param to indicate in analytics events that the user registered while enrolling in a particular course. Arguments: request (HTTPRequest) Returns: HttpResponse: 200 on success HttpResponse: 400 if the request is not valid. HttpResponse: 409 if an account with the given username or email address already exists HttpResponse: 403 operation not allowed """ data = request.POST.copy() email = data.get('email') username = data.get('username') # Handle duplicate email/username conflicts = check_account_exists(email=email, username=username) if conflicts: conflict_messages = { "email": _( # Translators: This message is shown to users who attempt to create a new # account using an email address associated with an existing account. u"It looks like {email_address} belongs to an existing account. " u"Try again with a different email address.").format( email_address=email), "username": _( # Translators: This message is shown to users who attempt to create a new # account using a username associated with an existing account. u"It looks like {username} belongs to an existing account. " u"Try again with a different username.").format( username=username), } errors = { field: [{ "user_message": conflict_messages[field] }] for field in conflicts } return JsonResponse(errors, status=409) # Backwards compatibility: the student view expects both # terms of service and honor code values. Since we're combining # these into a single checkbox, the only value we may get # from the new view is "honor_code". # Longer term, we will need to make this more flexible to support # open source installations that may have separate checkboxes # for TOS, privacy policy, etc. if data.get("honor_code") and "terms_of_service" not in data: data["terms_of_service"] = data["honor_code"] try: user = create_account_with_params(request, data) except ValidationError as err: # Should only get non-field errors from this function assert NON_FIELD_ERRORS not in err.message_dict # Only return first error for each field errors = { field: [{ "user_message": error } for error in error_list] for field, error_list in err.message_dict.items() } return JsonResponse(errors, status=400) except PermissionDenied: return HttpResponseForbidden(_("Account creation not allowed.")) response = JsonResponse({"success": True}) set_logged_in_cookies(request, response, user) return response
def post(self, request): """Create the user's account. You must send all required form fields with the request. You can optionally send a "course_id" param to indicate in analytics events that the user registered while enrolling in a particular course. Arguments: request (HTTPRequest) Returns: HttpResponse: 200 on success HttpResponse: 400 if the request is not valid. HttpResponse: 409 if an account with the given username or email address already exists """ data = request.POST.copy() email = data.get('email') username = data.get('username') # Handle duplicate email/username conflicts = check_account_exists(email=email, username=username) if conflicts: conflict_messages = { "email": _( # Translators: This message is shown to users who attempt to create a new # account using an email address associated with an existing account. u"It looks like {email_address} belongs to an existing account. " u"Try again with a different email address." ).format(email_address=email), "username": _( # Translators: This message is shown to users who attempt to create a new # account using a username associated with an existing account. u"It looks like {username} belongs to an existing account. " u"Try again with a different username." ).format(username=username), } errors = { field: [{"user_message": conflict_messages[field]}] for field in conflicts } return JsonResponse(errors, status=409) # Backwards compatibility: the student view expects both # terms of service and honor code values. Since we're combining # these into a single checkbox, the only value we may get # from the new view is "honor_code". # Longer term, we will need to make this more flexible to support # open source installations that may have separate checkboxes # for TOS, privacy policy, etc. if data.get("honor_code") and "terms_of_service" not in data: data["terms_of_service"] = data["honor_code"] try: user = create_account_with_params(request, data) except ValidationError as err: # Should only get non-field errors from this function assert NON_FIELD_ERRORS not in err.message_dict # Only return first error for each field errors = { field: [{"user_message": error} for error in error_list] for field, error_list in err.message_dict.items() } return JsonResponse(errors, status=400) response = JsonResponse({"success": True}) set_logged_in_cookies(request, response, user) return response
def post(self, request): """Create the user's account. You must send all required form fields with the request. You can optionally send a "course_id" param to indicate in analytics events that the user registered while enrolling in a particular course. Arguments: request (HTTPRequest) Returns: HttpResponse: 200 on success HttpResponse: 400 if the request is not valid. HttpResponse: 409 if an account with the given username or email address already exists HttpResponse: 403 operation not allowed """ import logging import datetime LOGGER = logging.getLogger(__name__) start_time = datetime.datetime.now() data = request.POST.copy() email = data.get('email') username = data.get('username') LOGGER.info( "*************** Request received for registration Username = {username}. Start time {start_time}: **************" .format(username=username, start_time=start_time)) # Handle duplicate email/username conflicts = check_account_exists(email=email, username=username) if conflicts: conflict_messages = { "email": accounts.EMAIL_CONFLICT_MSG.format(email_address=email), "username": accounts.USERNAME_CONFLICT_MSG.format(username=username), } errors = { field: [{ "user_message": conflict_messages[field] }] for field in conflicts } LOGGER.info( "*************** Registration failed for Username. Error: Username and email conflicts **************" .format(username=username)) return JsonResponse(errors, status=409) # Backwards compatibility: the student view expects both # terms of service and honor code values. Since we're combining # these into a single checkbox, the only value we may get # from the new view is "honor_code". # Longer term, we will need to make this more flexible to support # open source installations that may have separate checkboxes # for TOS, privacy policy, etc. if data.get("honor_code") and "terms_of_service" not in data: data["terms_of_service"] = data["honor_code"] try: user = create_account_with_params(request, data) except AccountValidationError as err: errors = {err.field: [{"user_message": text_type(err)}]} LOGGER.info( "*************** Registration failed for Username = {username}. Error: {error} **************" .format(username=username, error=err)) return JsonResponse(errors, status=409) except ValidationError as err: # Should only get non-field errors from this function assert NON_FIELD_ERRORS not in err.message_dict # Only return first error for each field errors = { field: [{ "user_message": error } for error in error_list] for field, error_list in err.message_dict.items() } LOGGER.info( "*************** Registration failed for Username = {username}. Error: {error} **************" .format(username=username, error=err)) return JsonResponse(errors, status=400) except PermissionDenied: LOGGER.info( "*************** Registration failed for Username. Error: PermissionDenied **************" .format(username=username)) return HttpResponseForbidden(_("Account creation not allowed.")) except Exception as err: LOGGER.exception( "*************** Registration failed for Username = {username}. Error: {error}" .format(username=username, error=err)) response = JsonResponse({"success": True}) set_logged_in_cookies(request, response, user) end_time = datetime.datetime.now() LOGGER.info( "*************** Request completed for registration Username = {username}. End time: {end_time} **************" .format(username=username, end_time=end_time)) time_diff = end_time - start_time LOGGER.info( "*************** Time Difference for User = {username}: {time_diff} **************" .format(username=username, time_diff=time_diff)) return response
def post(self, request): """Create the user's account. You must send all required form fields with the request. You can optionally send a "course_id" param to indicate in analytics events that the user registered while enrolling in a particular course. Arguments: request (HTTPRequest) Returns: HttpResponse: 200 on success HttpResponse: 400 if the request is not valid. HttpResponse: 409 if an account with the given username or email address already exists HttpResponse: 403 operation not allowed """ data = request.POST.copy() email = data.get('email') username = data.get('username') # Handle duplicate email/username conflicts = check_account_exists(email=email, username=username) if conflicts: conflict_messages = { "email": accounts.EMAIL_CONFLICT_MSG.format(email_address=email), "username": accounts.USERNAME_CONFLICT_MSG.format(username=username), } errors = { field: [{"user_message": conflict_messages[field]}] for field in conflicts } return JsonResponse(errors, status=409) # Backwards compatibility: the student view expects both # terms of service and honor code values. Since we're combining # these into a single checkbox, the only value we may get # from the new view is "honor_code". # Longer term, we will need to make this more flexible to support # open source installations that may have separate checkboxes # for TOS, privacy policy, etc. if data.get("honor_code") and "terms_of_service" not in data: data["terms_of_service"] = data["honor_code"] try: user = create_account_with_params(request, data) except AccountValidationError as err: errors = { err.field: [{"user_message": text_type(err)}] } return JsonResponse(errors, status=409) except ValidationError as err: # Should only get non-field errors from this function assert NON_FIELD_ERRORS not in err.message_dict # Only return first error for each field errors = { field: [{"user_message": error} for error in error_list] for field, error_list in err.message_dict.items() } return JsonResponse(errors, status=400) except PermissionDenied: return HttpResponseForbidden(_("Account creation not allowed.")) response = JsonResponse({"success": True}) set_logged_in_cookies(request, response, user) return response
def post(self, request): """Create the user's account. You must send all required form fields with the request. You can optionally send a "course_id" param to indicate in analytics events that the user registered while enrolling in a particular course. Arguments: request (HTTPRequest) Returns: HttpResponse: 200 on success HttpResponse: 400 if the request is not valid. HttpResponse: 409 if an account with the given username or email address already exists HttpResponse: 403 operation not allowed """ data = request.POST.copy() # Decrypt form data if it is encrypted if 'data_token' in request.POST: data_token = request.POST.get('data_token') try: decoded_data = jwt.decode( data_token, settings.EDRAAK_LOGISTRATION_SECRET_KEY, verify=False, algorithms=[ settings.EDRAAK_LOGISTRATION_SIGNING_ALGORITHM ]) data.update(decoded_data) except jwt.ExpiredSignatureError: err_msg = u"The provided data_token has been expired" log.warning(err_msg) return JsonResponse({ "success": False, "value": err_msg, }, status=400) except jwt.DecodeError: err_msg = u"Signature verification failed" log.warning(err_msg) return JsonResponse({ "success": False, "value": err_msg, }, status=400) except (jwt.InvalidTokenError, ValueError): err_msg = u"Invalid token" log.warning(err_msg) return JsonResponse({ "success": False, "value": err_msg, }, status=400) email = data.get('email') username = data.get('username') # Handle duplicate email/username conflicts = check_account_exists(email=email, username=username) if conflicts: conflict_messages = { "email": accounts.EMAIL_CONFLICT_MSG.format(email_address=email), "username": accounts.USERNAME_CONFLICT_MSG.format(username=username), } errors = { field: [{ "user_message": conflict_messages[field] }] for field in conflicts } return JsonResponse(errors, status=409) # Backwards compatibility: the student view expects both # terms of service and honor code values. Since we're combining # these into a single checkbox, the only value we may get # from the new view is "honor_code". # Longer term, we will need to make this more flexible to support # open source installations that may have separate checkboxes # for TOS, privacy policy, etc. if data.get("honor_code") and "terms_of_service" not in data: data["terms_of_service"] = data["honor_code"] try: user = create_account_with_params(request, data) except AccountValidationError as err: errors = {err.field: [{"user_message": text_type(err)}]} return JsonResponse(errors, status=409) except ValidationError as err: # Should only get non-field errors from this function assert NON_FIELD_ERRORS not in err.message_dict # Only return first error for each field errors = { field: [{ "user_message": error } for error in error_list] for field, error_list in err.message_dict.items() } return JsonResponse(errors, status=400) except PermissionDenied: return HttpResponseForbidden(_("Account creation not allowed.")) response = JsonResponse({"success": True}) set_logged_in_cookies(request, response, user) return response
def login_user_custom(request, error=""): # pylint: disable=too-many-statements,unused-argument """AJAX request to log in the user.""" backend_name = None email = None password = None redirect_url = None response = None running_pipeline = None third_party_auth_requested = third_party_auth.is_enabled( ) and pipeline.running(request) third_party_auth_successful = False trumped_by_first_party_auth = bool(request.POST.get('email')) or bool( request.POST.get('password')) user = None platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME) if third_party_auth_requested and not trumped_by_first_party_auth: # The user has already authenticated via third-party auth and has not # asked to do first party auth by supplying a username or password. We # now want to put them through the same logging and cookie calculation # logic as with first-party auth. running_pipeline = pipeline.get(request) username = running_pipeline['kwargs'].get('username') backend_name = running_pipeline['backend'] third_party_uid = running_pipeline['kwargs']['uid'] requested_provider = provider.Registry.get_from_pipeline( running_pipeline) try: user = pipeline.get_authenticated_user(requested_provider, username, third_party_uid) third_party_auth_successful = True except User.DoesNotExist: AUDIT_LOG.warning( u"Login failed - user with username {username} has no social auth " "with backend_name {backend_name}".format( username=username, backend_name=backend_name)) message = _( "You've successfully logged into your {provider_name} account, " "but this account isn't linked with an {platform_name} account yet." ).format( platform_name=platform_name, provider_name=requested_provider.name, ) message += "<br/><br/>" message += _( "Use your {platform_name} username and password to log into {platform_name} below, " "and then link your {platform_name} account with {provider_name} from your dashboard." ).format( platform_name=platform_name, provider_name=requested_provider.name, ) message += "<br/><br/>" message += _( "If you don't have an {platform_name} account yet, " "click <strong>Register</strong> at the top of the page." ).format(platform_name=platform_name) return HttpResponse(message, content_type="text/plain", status=403) else: if 'email' not in request.POST or 'password' not in request.POST: return JsonResponse({ "success": False, # TODO: User error message "value": _('There was an error receiving your login information. Please email us.' ), }) # TODO: this should be status code 400 email = request.POST['email'] password = request.POST['password'] try: user = User.objects.get(email=email) except User.DoesNotExist: if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.warning(u"Login failed - Unknown user email") else: AUDIT_LOG.warning( u"Login failed - Unknown user email: {0}".format(email)) # check if the user has a linked shibboleth account, if so, redirect the user to shib-login # This behavior is pretty much like what gmail does for shibboleth. Try entering some @stanford.edu # address into the Gmail login. if settings.FEATURES.get('AUTH_USE_SHIB') and user: try: eamap = ExternalAuthMap.objects.get(user=user) if eamap.external_domain.startswith( openedx.core.djangoapps.external_auth.views. SHIBBOLETH_DOMAIN_PREFIX): return JsonResponse({ "success": False, "redirect": reverse('shib-login'), }) # TODO: this should be status code 301 # pylint: disable=fixme except ExternalAuthMap.DoesNotExist: # This is actually the common case, logging in user without external linked login AUDIT_LOG.info(u"User %s w/o external auth attempting login", user) # see if account has been locked out due to excessive login failures user_found_by_email_lookup = user if user_found_by_email_lookup and LoginFailures.is_feature_enabled(): if LoginFailures.is_user_locked_out(user_found_by_email_lookup): lockout_message = _( 'This account has been temporarily locked due ' 'to excessive login failures. Try again later.') return JsonResponse({ "success": False, "value": lockout_message, }) # TODO: this should be status code 429 # pylint: disable=fixme # see if the user must reset his/her password due to any policy settings if user_found_by_email_lookup and PasswordHistory.should_user_reset_password_now( user_found_by_email_lookup): return JsonResponse({ "success": False, "value": _('Your password has expired due to password policy on this account. You must ' 'reset your password before you can log in again. Please click the ' '"Forgot Password" link on this page to reset your password before logging in again.' ), }) # TODO: this should be status code 403 # pylint: disable=fixme # if the user doesn't exist, we want to set the username to an invalid # username so that authentication is guaranteed to fail and we can take # advantage of the ratelimited backend username = user.username if user else "" if not third_party_auth_successful: try: user = authenticate(username=username, password=password, request=request) # this occurs when there are too many attempts from the same IP address except RateLimitException: return JsonResponse({ "success": False, "value": _('Too many failed login attempts. Try again later.'), }) # TODO: this should be status code 429 # pylint: disable=fixme if user is None: # tick the failed login counters if the user exists in the database if user_found_by_email_lookup and LoginFailures.is_feature_enabled(): LoginFailures.increment_lockout_counter(user_found_by_email_lookup) # if we didn't find this username earlier, the account for this email # doesn't exist, and doesn't have a corresponding password if username != "": if settings.FEATURES['SQUELCH_PII_IN_LOGS']: loggable_id = user_found_by_email_lookup.id if user_found_by_email_lookup else "<unknown>" AUDIT_LOG.warning( u"Login failed - password for user.id: {0} is invalid". format(loggable_id)) else: AUDIT_LOG.warning( u"Login failed - password for {0} is invalid".format( email)) return JsonResponse({ "success": False, "value": _('Email or password is incorrect.'), }) # TODO: this should be status code 400 # pylint: disable=fixme # successful login, clear failed login attempts counters, if applicable if LoginFailures.is_feature_enabled(): LoginFailures.clear_lockout_counter(user) # Track the user's sign in if hasattr(settings, 'LMS_SEGMENT_KEY') and settings.LMS_SEGMENT_KEY: tracking_context = tracker.get_tracker().resolve_context() analytics.identify( user.id, { 'email': email, 'username': username }, { # Disable MailChimp because we don't want to update the user's email # and username in MailChimp on every page load. We only need to capture # this data on registration/activation. 'MailChimp': False }) analytics.track(user.id, "edx.bi.user.account.authenticated", { 'category': "conversion", 'label': request.POST.get('course_id'), 'provider': None }, context={ 'ip': tracking_context.get('ip'), 'Google Analytics': { 'clientId': tracking_context.get('client_id') } }) if user is not None and user.is_active: try: # We do not log here, because we have a handler registered # to perform logging on successful logins. login(request, user) if request.POST.get('remember') == 'true': request.session.set_expiry(604800) log.debug("Setting user session to never expire") else: request.session.set_expiry(0) except Exception as exc: # pylint: disable=broad-except AUDIT_LOG.critical( "Login failed - Could not create session. Is memcached running?" ) log.critical( "Login failed - Could not create session. Is memcached running?" ) log.exception(exc) raise redirect_url = None # The AJAX method calling should know the default destination upon success if third_party_auth_successful: redirect_url = pipeline.get_complete_url(backend_name) response = JsonResponse({ "success": True, "redirect_url": redirect_url, }) # Ensure that the external marketing site can # detect that the user is logged in. return set_logged_in_cookies(request, response, user) if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.warning( u"Login failed - Account not active for user.id: {0}, resending activation" .format(user.id)) else: AUDIT_LOG.warning( u"Login failed - Account not active for user {0}, resending activation" .format(username)) reactivation_email_for_user_custom(request, user) not_activated_msg = _( "Before you sign in, you need to activate your account. We have sent you an " "email message with instructions for activating your account.") return JsonResponse({ "success": False, "value": not_activated_msg, }) # TODO: this should be status code 400 # pylint: disable=fixme
def login_user(request): """ AJAX request to log in the user. """ post_data = request.POST.copy() # Decrypt form data if it is encrypted if 'data_token' in request.POST: data_token = request.POST.get('data_token') try: decoded_data = jwt.decode( data_token, settings.EDRAAK_LOGISTRATION_SECRET_KEY, verify=False, algorithms=[settings.EDRAAK_LOGISTRATION_SIGNING_ALGORITHM]) post_data.update(decoded_data) except jwt.ExpiredSignatureError: err_msg = u"The provided data_token has been expired" AUDIT_LOG.warning(err_msg) return JsonResponse({ "success": False, "value": err_msg, }, status=400) except jwt.DecodeError: err_msg = u"Signature verification failed" AUDIT_LOG.warning(err_msg) return JsonResponse({ "success": False, "value": err_msg, }, status=400) except (jwt.InvalidTokenError, ValueError): err_msg = u"Invalid token" AUDIT_LOG.warning(err_msg) return JsonResponse({ "success": False, "value": err_msg, }, status=400) third_party_auth_requested = third_party_auth.is_enabled( ) and pipeline.running(request) trumped_by_first_party_auth = bool(post_data.get('email')) or bool( post_data.get('password')) was_authenticated_third_party = False parent_user = None child_user = None try: if third_party_auth_requested and not trumped_by_first_party_auth: # The user has already authenticated via third-party auth and has not # asked to do first party auth by supplying a username or password. We # now want to put them through the same logging and cookie calculation # logic as with first-party auth. # This nested try is due to us only returning an HttpResponse in this # one case vs. JsonResponse everywhere else. try: email_user = _do_third_party_auth(request) was_authenticated_third_party = True except AuthFailedError as e: return HttpResponse(e.value, content_type="text/plain", status=403) elif 'child_user_id' in post_data: child_user_id = post_data['child_user_id'] try: child_user = User.objects.get(id=child_user_id) except User.DoesNotExist: if settings.FEATURES['SQUELCH_PII_IN_LOGS']: AUDIT_LOG.warning( u"Child login failed - Unknown child user id") else: AUDIT_LOG.warning( u"Child login failed - Unknown child user id: {0}". format(child_user_id)) else: email_user = _get_user_by_email(request, post_data=post_data) if child_user: parent_user = request.user email_user = child_user _check_shib_redirect(email_user) _check_excessive_login_attempts(email_user) _check_forced_password_reset(email_user) # set the user object to child_user object if a child is being logged in possibly_authenticated_user = email_user if not was_authenticated_third_party: possibly_authenticated_user = _authenticate_first_party( request, post_data, email_user) if possibly_authenticated_user and password_policy_compliance.should_enforce_compliance_on_login( ): # Important: This call must be made AFTER the user was successfully authenticated. _enforce_password_policy_compliance( request, post_data, possibly_authenticated_user) if possibly_authenticated_user is None or not possibly_authenticated_user.is_active: _handle_failed_authentication(email_user) _handle_successful_authentication_and_login( possibly_authenticated_user, request, post_data) if parent_user: request.session['parent_user'] = json.dumps({ 'user_id': parent_user.id, 'username': parent_user.username, 'email': parent_user.email, 'name': parent_user.profile.name }) redirect_url = None # The AJAX method calling should know the default destination upon success if was_authenticated_third_party: running_pipeline = pipeline.get(request) redirect_url = pipeline.get_complete_url( backend_name=running_pipeline['backend']) response = JsonResponse({ 'success': True, 'redirect_url': redirect_url, }) # Ensure that the external marketing site can # detect that the user is logged in. return set_logged_in_cookies(request, response, possibly_authenticated_user) except AuthFailedError as error: return JsonResponse(error.get_response())