def auto_auth(request): """ Create or configure a user account, then log in as that user. Enabled only when settings.FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] is true. Accepts the following querystring parameters: * `username`, `email`, and `password` for the user account * `full_name` for the user profile (the user's full name; defaults to the username) * `staff`: Set to "true" to make the user global staff. * `course_id`: Enroll the student in the course with `course_id` * `roles`: Comma-separated list of roles to grant the student in the course with `course_id` * `no_login`: Define this to create the user but not login * `redirect`: Set to "true" will redirect to the `redirect_to` value if set, or course home page if course_id is defined, otherwise it will redirect to dashboard * `redirect_to`: will redirect to to this url * `is_active` : make/update account with status provided as 'is_active' If username, email, or password are not provided, use randomly generated credentials. """ # Generate a unique name to use if none provided generated_username = uuid.uuid4().hex[0:30] generated_password = generate_password() # Use the params from the request, otherwise use these defaults username = request.GET.get('username', generated_username) password = request.GET.get('password', generated_password) email = request.GET.get('email', username + "@example.com") full_name = request.GET.get('full_name', username) is_staff = str2bool(request.GET.get('staff', False)) is_superuser = str2bool(request.GET.get('superuser', False)) course_id = request.GET.get('course_id') redirect_to = request.GET.get('redirect_to') is_active = str2bool(request.GET.get('is_active', True)) # Valid modes: audit, credit, honor, no-id-professional, professional, verified enrollment_mode = request.GET.get('enrollment_mode', 'honor') # Parse roles, stripping whitespace, and filtering out empty strings roles = _clean_roles(request.GET.get('roles', '').split(',')) course_access_roles = _clean_roles(request.GET.get('course_access_roles', '').split(',')) redirect_when_done = str2bool(request.GET.get('redirect', '')) or redirect_to login_when_done = 'no_login' not in request.GET form = AccountCreationForm( data={ 'username': username, 'email': email, 'password': password, 'confirm_password': password, 'name': full_name, }, tos_required=False ) # Attempt to create the account. # If successful, this will return a tuple containing # the new user object. try: user, profile, reg = do_create_account(form) except (AccountValidationError, ValidationError): # Attempt to retrieve the existing user. user = User.objects.get(username=username) user.email = email user.set_password(password) user.is_active = is_active user.save() profile = UserProfile.objects.get(user=user) reg = Registration.objects.get(user=user) except PermissionDenied: return HttpResponseForbidden(_('Account creation not allowed.')) user.is_staff = is_staff user.is_superuser = is_superuser user.save() if is_active: reg.activate() reg.save() # ensure parental consent threshold is met year = datetime.date.today().year age_limit = settings.PARENTAL_CONSENT_AGE_LIMIT profile.year_of_birth = (year - age_limit) - 1 profile.save() create_or_set_user_attribute_created_on_site(user, request.site) # Enroll the user in a course course_key = None if course_id: course_key = CourseLocator.from_string(course_id) CourseEnrollment.enroll(user, course_key, mode=enrollment_mode) # Apply the roles for role in roles: assign_role(course_key, user, role) for role in course_access_roles: CourseAccessRole.objects.update_or_create(user=user, course_id=course_key, org=course_key.org, role=role) # Log in as the user if login_when_done: user = authenticate_new_user(request, username, password) django_login(request, user) create_comments_service_user(user) if redirect_when_done: if redirect_to: # Redirect to page specified by the client redirect_url = redirect_to elif course_id: # Redirect to the course homepage (in LMS) or outline page (in Studio) try: redirect_url = reverse(course_home_url_name(course_key), kwargs={'course_id': course_id}) except NoReverseMatch: redirect_url = reverse('course_handler', kwargs={'course_key_string': course_id}) else: # Redirect to the learner dashboard (in LMS) or homepage (in Studio) try: redirect_url = reverse('dashboard') except NoReverseMatch: redirect_url = reverse('home') return redirect(redirect_url) else: response = JsonResponse({ 'created_status': 'Logged in' if login_when_done else 'Created', 'username': username, 'email': email, 'password': password, 'user_id': user.id, # pylint: disable=no-member 'anonymous_id': anonymous_id_for_user(user, None), }) response.set_cookie('csrftoken', csrf(request)['csrf_token']) return response
response = JsonResponse({ 'success': True, 'redirect_url': redirect_url, }) # set the login cookie for the edx marketing site # we want this cookie to be accessed via javascript # so httponly is set to None if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = cookie_date(expires_time) response.set_cookie(settings.EDXMKTG_COOKIE_NAME, 'true', max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path='/', secure=None, httponly=None) return response views.create_account = create_account
def auto_auth(request): """ Create or configure a user account, then log in as that user. Enabled only when settings.FEATURES['AUTOMATIC_AUTH_FOR_TESTING'] is true. Accepts the following querystring parameters: * `username`, `email`, and `password` for the user account * `full_name` for the user profile (the user's full name; defaults to the username) * `staff`: Set to "true" to make the user global staff. * `course_id`: Enroll the student in the course with `course_id` * `roles`: Comma-separated list of roles to grant the student in the course with `course_id` * `no_login`: Define this to create the user but not login * `redirect`: Set to "true" will redirect to the `redirect_to` value if set, or course home page if course_id is defined, otherwise it will redirect to dashboard * `redirect_to`: will redirect to to this url * `is_active` : make/update account with status provided as 'is_active' If username, email, or password are not provided, use randomly generated credentials. """ # Generate a unique name to use if none provided generated_username = uuid.uuid4().hex[0:30] generated_password = generate_password() # Use the params from the request, otherwise use these defaults username = request.GET.get('username', generated_username) password = request.GET.get('password', generated_password) email = request.GET.get('email', username + "@example.com") full_name = request.GET.get('full_name', username) is_staff = str2bool(request.GET.get('staff', False)) is_superuser = str2bool(request.GET.get('superuser', False)) course_id = request.GET.get('course_id') redirect_to = request.GET.get('redirect_to') is_active = str2bool(request.GET.get('is_active', True)) # Valid modes: audit, credit, honor, no-id-professional, professional, verified enrollment_mode = request.GET.get('enrollment_mode', 'honor') # Parse roles, stripping whitespace, and filtering out empty strings roles = _clean_roles(request.GET.get('roles', '').split(',')) course_access_roles = _clean_roles(request.GET.get('course_access_roles', '').split(',')) redirect_when_done = str2bool(request.GET.get('redirect', '')) or redirect_to login_when_done = 'no_login' not in request.GET restricted = settings.FEATURES.get('RESTRICT_AUTOMATIC_AUTH', True) if is_superuser and restricted: return HttpResponseForbidden(_('Superuser creation not allowed')) form = AccountCreationForm( data={ 'username': username, 'email': email, 'password': password, 'name': full_name, }, tos_required=False ) # Attempt to create the account. # If successful, this will return a tuple containing # the new user object. try: user, profile, reg = do_create_account(form) except (AccountValidationError, ValidationError): if restricted: return HttpResponseForbidden(_('Account modification not allowed.')) # Attempt to retrieve the existing user. user = User.objects.get(username=username) user.email = email user.set_password(password) user.is_active = is_active user.save() profile = UserProfile.objects.get(user=user) reg = Registration.objects.get(user=user) except PermissionDenied: return HttpResponseForbidden(_('Account creation not allowed.')) user.is_staff = is_staff user.is_superuser = is_superuser user.save() if is_active: reg.activate() reg.save() # ensure parental consent threshold is met year = datetime.date.today().year age_limit = settings.PARENTAL_CONSENT_AGE_LIMIT profile.year_of_birth = (year - age_limit) - 1 profile.save() create_or_set_user_attribute_created_on_site(user, request.site) # Enroll the user in a course course_key = None if course_id: course_key = CourseLocator.from_string(course_id) CourseEnrollment.enroll(user, course_key, mode=enrollment_mode) # Apply the roles for role in roles: assign_role(course_key, user, role) for role in course_access_roles: CourseAccessRole.objects.update_or_create(user=user, course_id=course_key, org=course_key.org, role=role) # Log in as the user if login_when_done: user = authenticate_new_user(request, username, password) django_login(request, user) create_comments_service_user(user) if redirect_when_done: if redirect_to: # Redirect to page specified by the client redirect_url = redirect_to elif course_id: # Redirect to the course homepage (in LMS) or outline page (in Studio) try: redirect_url = reverse(course_home_url_name(course_key), kwargs={'course_id': course_id}) except NoReverseMatch: redirect_url = reverse('course_handler', kwargs={'course_key_string': course_id}) else: # Redirect to the learner dashboard (in LMS) or homepage (in Studio) try: redirect_url = reverse('dashboard') except NoReverseMatch: redirect_url = reverse('home') return redirect(redirect_url) else: response = JsonResponse({ 'created_status': 'Logged in' if login_when_done else 'Created', 'username': username, 'email': email, 'password': password, 'user_id': user.id, # pylint: disable=no-member 'anonymous_id': anonymous_id_for_user(user, None), }) response.set_cookie('csrftoken', csrf(request)['csrf_token']) return response
def post(request, error=""): # pylint: disable-msg=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 = settings.FEATURES.get('ENABLE_THIRD_PARTY_AUTH') 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 if 'email' not in request.POST or 'password' not in request.POST: return JsonResponse({ "success": False, "value": _('There was an error receiving your login information. Please email us.'), # TODO: User error message }) # TODO: this should be status code 400 # pylint: disable=fixme 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)) # 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): return JsonResponse({ "success": False, "value": _('This account has been temporarily locked due to excessive login failures. Try again later.'), }) # 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 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) 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 e: 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(e) raise response = JsonResponse({ "success": True, "username": user.username, "email": user.email }) # set the login cookie for the edx marketing site # we want this cookie to be accessed via javascript # so httponly is set to None if request.session.get_expire_at_browser_close(): max_age = None expires = None else: max_age = request.session.get_expiry_age() expires_time = time.time() + max_age expires = cookie_date(expires_time) response.set_cookie( settings.EDXMKTG_COOKIE_NAME, 'true', max_age=max_age, expires=expires, domain=settings.SESSION_COOKIE_DOMAIN, path='/', secure=None, httponly=None, ) return response 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(user) not_activated_msg = _("This account has not been activated. We have sent another activation message. Please check your e-mail for the activation instructions.") return JsonResponse({ "success": False, "value": not_activated_msg, }) # TODO: this should be status code 400 # pylint: disable=fixme