Exemplo n.º 1
0
    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()
        self._handle_terms_of_service(data)

        response = self._handle_duplicate_email_username(request, data)
        if response:
            return response

        response, user = self._create_account(request, data)
        if response:
            return response

        response = self._create_response(request, {}, status_code=200)
        set_logged_in_cookies(request, response, user)
        return response
Exemplo n.º 2
0
    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
        """
        should_be_rate_limited = getattr(request, 'limited', False)
        if should_be_rate_limited:
            return JsonResponse({'error_code': 'forbidden-request'},
                                status=403)

        if is_require_third_party_auth_enabled(
        ) and not pipeline.running(request):
            # if request is not running a third-party auth pipeline
            return HttpResponseForbidden(
                "Third party authentication is required to register. Username and password were received instead."
            )

        data = request.POST.copy()
        self._handle_terms_of_service(data)

        response = self._handle_duplicate_email_username(request, data)
        if response:
            return response

        response, user = self._create_account(request, data)
        if response:
            return response

        redirect_to, root_url = get_next_url_for_login_page(request,
                                                            include_host=True)
        redirect_url = get_redirect_url_with_host(root_url, redirect_to)
        response = self._create_response(request, {},
                                         status_code=200,
                                         redirect_url=redirect_url)
        set_logged_in_cookies(request, response, user)
        if not user.is_active and settings.SHOW_ACCOUNT_ACTIVATION_CTA and not settings.MARKETING_EMAILS_OPT_IN:
            response.set_cookie(
                settings.SHOW_ACTIVATE_CTA_POPUP_COOKIE_NAME,
                True,
                domain=settings.SESSION_COOKIE_DOMAIN,
                path='/',
                secure=request.is_secure()
            )  # setting the cookie to show account activation dialogue in platform and learning MFE
        mark_user_change_as_expected(response, user.id)
        return response
Exemplo n.º 3
0
def create_account(request, post_override=None):
    """
    Deprecated. Use RegistrationView instead.
    JSON call to create new edX account.
    Used by form in signup_modal.html, which is included into header.html
    """
    # Check if ALLOW_PUBLIC_ACCOUNT_CREATION flag turned off to restrict user account creation
    if not configuration_helpers.get_value(
            'ALLOW_PUBLIC_ACCOUNT_CREATION',
            settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)):
        return HttpResponseForbidden(_("Account creation not allowed."))

    if waffle().is_enabled(PREVENT_AUTH_USER_WRITES):
        return HttpResponseForbidden(SYSTEM_MAINTENANCE_MSG)

    warnings.warn("Please use RegistrationView instead.", DeprecationWarning)

    try:
        user = create_account_with_params(request, post_override
                                          or request.POST)
    except AccountValidationError as exc:
        return JsonResponse(
            {
                'success': False,
                'value': text_type(exc),
                'field': exc.field
            },
            status=400)
    except ValidationError as exc:
        field, error_list = next(iteritems(exc.message_dict))
        return JsonResponse(
            {
                "success": False,
                "field": field,
                "value": ' '.join(error_list),
            },
            status=400)

    redirect_url = None  # The AJAX method calling should know the default destination upon success

    # Resume the third-party-auth pipeline if necessary.
    if third_party_auth.is_enabled() and pipeline.running(request):
        running_pipeline = pipeline.get(request)
        redirect_url = pipeline.get_complete_url(running_pipeline['backend'])

    response = JsonResponse({
        'success': True,
        'redirect_url': redirect_url,
    })
    set_logged_in_cookies(request, response, user)
    return response
Exemplo n.º 4
0
    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
        """
        should_be_rate_limited = getattr(request, 'limited', False)
        if should_be_rate_limited:
            return JsonResponse({'error_code': 'forbidden-request'},
                                status=403)

        if is_require_third_party_auth_enabled(
        ) and not pipeline.running(request):
            # if request is not running a third-party auth pipeline
            return HttpResponseForbidden(
                "Third party authentication is required to register. Username and password were received instead."
            )

        data = request.POST.copy()
        self._handle_terms_of_service(data)

        response = self._handle_duplicate_email_username(request, data)
        if response:
            return response

        response, user = self._create_account(request, data)
        if response:
            return response

        redirect_to, root_url = get_next_url_for_login_page(request,
                                                            include_host=True)
        redirect_url = get_redirect_url_with_host(root_url, redirect_to)
        response = self._create_response(request, {},
                                         status_code=200,
                                         redirect_url=redirect_url)
        set_logged_in_cookies(request, response, user)
        return response
Exemplo n.º 5
0
 def test_set_logged_in_deprecated_cookies(self):
     response = cookies_api.set_logged_in_cookies(self.request,
                                                  HttpResponse(), self.user)
     self._assert_cookies_present(
         response, cookies_api.DEPRECATED_LOGGED_IN_COOKIE_NAMES)
     self._assert_consistent_expires(response)
     self._assert_recreate_jwt_from_cookies(response, can_recreate=False)
Exemplo n.º 6
0
def do_login(request, user):
    # _track_user_login(user, request)
    try:
        django_login(request, user, backend="django.contrib.auth.backends.ModelBackend")
        request.session.set_expiry(604800)
        request.user = user
        user_extra_data = userdetails(user.id)
        response = JsonResponse(
            {
                "success": True,
                "redirect_url": request.POST.get("redirect_url", ""),
                "status": 200,
                "email": user.email,
                "phone": user_extra_data.phone,
            }
        )
        logs.info(u"phone--> %s", user_extra_data.phone)
        return set_logged_in_cookies(request, response, user)
        logs.debug("Setting user session to never expire")
    except Exception as exc:  # pylint: disable=broad-except
        AUDIT_LOG.critical(
            "Login failed - Could not create session. Is memcached running?"
        )
        logs.critical("Login failed - Could not create session. Is memcached running?")
        logs.exception(exc)
Exemplo n.º 7
0
 def test_set_logged_in_jwt_cookies(self):
     setup_login_oauth_client()
     self._set_use_jwt_cookie_header(self.request)
     response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user)
     self._assert_cookies_present(response, cookies_api.ALL_LOGGED_IN_COOKIE_NAMES)
     self._assert_consistent_expires(response, num_of_unique_expires=2)
     self._assert_recreate_jwt_from_cookies(response, can_recreate=True)
Exemplo n.º 8
0
def login_user(request):
    """
    AJAX request to log in the user.
    """
    third_party_auth_requested = third_party_auth.is_enabled() and pipeline.running(request)
    first_party_auth_requested = bool(request.POST.get('email')) or bool(request.POST.get('password'))
    is_user_third_party_authenticated = False

    try:
        if third_party_auth_requested and not first_party_auth_requested:
            # 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:
                user = _do_third_party_auth(request)
                is_user_third_party_authenticated = True
            except AuthFailedError as e:
                return HttpResponse(e.value, content_type="text/plain", status=403)
        else:
            user = _get_user_by_email(request)

        _check_shib_redirect(user)
        _check_excessive_login_attempts(user)

        possibly_authenticated_user = user

        if not is_user_third_party_authenticated:
            possibly_authenticated_user = _authenticate_first_party(request, 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(user, possibly_authenticated_user)

        if not is_edly_user_allowed_to_login(request, possibly_authenticated_user):
            raise AuthFailedError(_('You are not allowed to login on this site.'))

        _handle_successful_authentication_and_login(possibly_authenticated_user, request)

        redirect_url = None  # The AJAX method calling should know the default destination upon success
        if is_user_third_party_authenticated:
            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:
        log.exception(error.get_response())
        return JsonResponse(error.get_response())
Exemplo n.º 9
0
 def test_set_logged_in_jwt_cookies(self):
     setup_login_oauth_client()
     self._set_use_jwt_cookie_header(self.request)
     response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user)
     self._assert_cookies_present(response, cookies_api.ALL_LOGGED_IN_COOKIE_NAMES)
     self._assert_consistent_expires(response)
     self._assert_recreate_jwt_from_cookies(response, can_recreate=True)
Exemplo n.º 10
0
 def test_set_logged_in_jwt_cookies(self):
     setup_login_oauth_client()
     with cookies_api.JWT_COOKIES_FLAG.override(True):
         response = cookies_api.set_logged_in_cookies(
             self.request, HttpResponse(), self.user)
         self._assert_cookies_present(
             response, cookies_api.ALL_LOGGED_IN_COOKIE_NAMES)
         self._assert_recreate_jwt_from_cookies(response, can_recreate=True)
Exemplo n.º 11
0
def create_account(request, post_override=None):
    """
    Deprecated. Use RegistrationView instead.
    JSON call to create new edX account.
    Used by form in signup_modal.html, which is included into header.html
    """
    # Check if ALLOW_PUBLIC_ACCOUNT_CREATION flag turned off to restrict user account creation
    if not configuration_helpers.get_value(
            'ALLOW_PUBLIC_ACCOUNT_CREATION',
            settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)
    ):
        return HttpResponseForbidden(_("Account creation not allowed."))

    if waffle().is_enabled(PREVENT_AUTH_USER_WRITES):
        return HttpResponseForbidden(SYSTEM_MAINTENANCE_MSG)

    warnings.warn("Please use RegistrationView instead.", DeprecationWarning)

    try:
        user = create_account_with_params(request, post_override or request.POST)
    except AccountValidationError as exc:
        return JsonResponse({'success': False, 'value': text_type(exc), 'field': exc.field}, status=400)
    except ValidationError as exc:
        field, error_list = next(iteritems(exc.message_dict))
        return JsonResponse(
            {
                "success": False,
                "field": field,
                "value": ' '.join(error_list),
            },
            status=400
        )

    redirect_url = None  # The AJAX method calling should know the default destination upon success

    # Resume the third-party-auth pipeline if necessary.
    if third_party_auth.is_enabled() and pipeline.running(request):
        running_pipeline = pipeline.get(request)
        redirect_url = pipeline.get_complete_url(running_pipeline['backend'])

    response = JsonResponse({
        'success': True,
        'redirect_url': redirect_url,
    })
    set_logged_in_cookies(request, response, user)
    return response
Exemplo n.º 12
0
    def test_delete_and_is_logged_in_cookie_set(self):
        response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user)
        self._copy_cookies_to_request(response, self.request)
        self.assertTrue(cookies_api.is_logged_in_cookie_set(self.request))

        cookies_api.delete_logged_in_cookies(response)
        self._copy_cookies_to_request(response, self.request)
        self.assertFalse(cookies_api.is_logged_in_cookie_set(self.request))
Exemplo n.º 13
0
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:
        log.exception(error.get_response())
        return JsonResponse(error.get_response())
Exemplo n.º 14
0
    def test_delete_and_is_logged_in_cookie_set(self):
        response = cookies_api.set_logged_in_cookies(self.request,
                                                     HttpResponse(), self.user)
        self._copy_cookies_to_request(response, self.request)
        self.assertTrue(cookies_api.is_logged_in_cookie_set(self.request))

        cookies_api.delete_logged_in_cookies(response)
        self._copy_cookies_to_request(response, self.request)
        self.assertFalse(cookies_api.is_logged_in_cookie_set(self.request))
Exemplo n.º 15
0
    def test_delete_and_are_logged_in_cookies_set(self):
        setup_login_oauth_client()
        response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user)
        self._copy_cookies_to_request(response, self.request)
        self.assertTrue(cookies_api.are_logged_in_cookies_set(self.request))

        cookies_api.delete_logged_in_cookies(response)
        self._copy_cookies_to_request(response, self.request)
        self.assertFalse(cookies_api.are_logged_in_cookies_set(self.request))
Exemplo n.º 16
0
    def test_delete_and_are_logged_in_cookies_set(self):
        setup_login_oauth_client()
        response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user)
        self._copy_cookies_to_request(response, self.request)
        self.assertTrue(cookies_api.are_logged_in_cookies_set(self.request))

        cookies_api.delete_logged_in_cookies(response)
        self._copy_cookies_to_request(response, self.request)
        self.assertFalse(cookies_api.are_logged_in_cookies_set(self.request))
Exemplo n.º 17
0
def set_logged_in_cookies(
        backend=None,
        user=None,
        strategy=None,
        auth_entry=None,
        current_partial=None,  # lint-amnesty, pylint: disable=keyword-arg-before-vararg
        *args,
        **kwargs):
    """This pipeline step sets the "logged in" cookie for authenticated users.

    Some installations have a marketing site front-end separate from
    edx-platform.  Those installations sometimes display different
    information for logged in versus anonymous users (e.g. a link
    to the student dashboard instead of the login page.)

    Since social auth uses Django's native `login()` method, it bypasses
    our usual login view that sets this cookie.  For this reason, we need
    to set the cookie ourselves within the pipeline.

    The procedure for doing this is a little strange.  On the one hand,
    we need to send a response to the user in order to set the cookie.
    On the other hand, we don't want to drop the user out of the pipeline.

    For this reason, we send a redirect back to the "complete" URL,
    so users immediately re-enter the pipeline.  The redirect response
    contains a header that sets the logged in cookie.

    If the user is not logged in, or the logged in cookie is already set,
    the function returns `None`, indicating that control should pass
    to the next pipeline step.

    """
    if not is_api(auth_entry) and user is not None and user.is_authenticated:
        request = strategy.request if strategy else None
        if not user.has_usable_password():
            msg = "Your account is disabled"
            logout(request)
            return JsonResponse(msg, status=403)
        # n.b. for new users, user.is_active may be False at this point; set the cookie anyways.
        if request is not None:
            # Check that the cookie isn't already set.
            # This ensures that we allow the user to continue to the next
            # pipeline step once he/she has the cookie set by this step.
            has_cookie = user_authn_cookies.are_logged_in_cookies_set(request)
            if not has_cookie:
                try:
                    redirect_url = get_complete_url(current_partial.backend)
                except ValueError:
                    # If for some reason we can't get the URL, just skip this step
                    # This may be overly paranoid, but it's far more important that
                    # the user log in successfully than that the cookie is set.
                    pass
                else:
                    response = redirect(redirect_url)
                    return user_authn_cookies.set_logged_in_cookies(
                        request, response, user)
Exemplo n.º 18
0
def docvid_login(request, user, courseid):
    # _track_user_login(user, request)
    try:
        request.session.set_expiry(604800)
        django_login(request,
                     user,
                     backend="django.contrib.auth.backends.ModelBackend")
        # request.session.set_expiry(604800)
        request.user = user
        user_extra_data = userdetails(user.id)
        course_id = request.data.get("course_id", "")
        course_id = course_id.replace(" ", "+")
        logs.info("course_id %s", course_id)
        course_key = None
        if course_id:
            course_key = CourseKey.from_string(course_id)
            try:
                check_enrollment = CourseEnrollment.objects.get(
                    user=request.user, course_id=course_key)
            except:
                try:
                    course_mode = CourseMode.objects.get(course_id=course_key)
                    CourseEnrollment.enroll(user,
                                            course_key,
                                            mode=course_mode.mode)
                except:
                    CourseEnrollment.enroll(user, course_key, mode="audit")
        redirect_url = ("https://docvidya.learn.docmode.org/courses/" +
                        course_id + "/courseware")
        # redirect_url = "https://develop.docmode.org/login?next=/oauth2/authorize/confirm"
        # datags = JsonResponse({
        #     'success': True,
        #     'redirect_url':redirect_url,
        #     'status': 200,
        #     'email':user.email
        # })
        # cookie = set_logged_in_cookies(request, datags, user)
        # cookie = cookie.cookies
        # logs.info(u'cookie--> %s', cookie)
        response = JsonResponse({
            "success": True,
            "redirect_url": redirect_url,
            "status": 200,
            "email": user.email,
        })
        logs.info(u"phone--> %s", user_extra_data.phone)
        return set_logged_in_cookies(request, response, user)
        # logs.info(u'loggedin--> %s', loggedin.__dict__)
        # return loggedin
        logs.debug("Setting user session to never expire")
    except Exception as exc:  # pylint: disable=broad-except
        # AUDIT_LOG.critical("Login failed - Could not create session. Is memcached running?")
        logs.critical(
            "Login failed - Could not create session. Is memcached running?")
        logs.exception(exc)
Exemplo n.º 19
0
def docvid_login(request, user,courseid):
    # _track_user_login(user, request)
    try:
        if not request.user.is_authenticated:
            request.session.set_expiry(604800)
            django_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
        else:
            logout(request)
            request.session.set_expiry(604800)
            django_login(request, user, backend='django.contrib.auth.backends.ModelBackend')
        #request.session.set_expiry(604800)
        request.user = user
        #logs.info('userid--> %s',request.user)
        user_extra_data = userdetails(user.id)
        displayname = getuserfullprofile(user.id)
        course_id = request.data.get('course_id','')
        course_id = course_id.replace(' ','+')
        #logs.info('course_id %s',course_id)
        course_key = None
        if course_id:
            course_key = CourseKey.from_string(course_id)
            if not CourseEnrollment.is_enrolled(user, course_key) :
                user_course_enrollment = CourseEnrollment.enroll(user=user, course_key=course_key,mode='honor')
            # else:
                
            #     query = course_id.replace('+','%2B')
            #     query = query.replace(':','%3A')
            #     now_asia = courseid.start.astimezone(timezone('Asia/Kolkata'))
                
            #     docvidya_course_detail = requests.get('https://drlprdoce-drreddys.cec.ocp.oraclecloud.com//content/published/api/v1.1/items?fields=slug&orderBy=updateddate:desc&limit=1&q=((type eq "DocV-Courses") and (fields.course_id eq "' + query + '"))&channelToken=cf84462f73e542e7a8d270dfd2580730')
            #     response = json.loads(docvidya_course_detail.text.encode('utf8'))
            #     courseurl = request.session['drl_http_referer']+'/docv-courses-detail/'+response['items'][0]['slug']
            #     courseurl = courseurl.replace('https://','')
            #     #logs.info("docvidya_course_detail--> %s",response['items'][0]['slug'])
            #     enrolldata = CourseEnrollment.objects.get(user=user,course_id=course_key)
            #     course_image_url = courseid.course_image_url.replace('+','%2B')
            #     logs.info("starttime-->%s",now_asia.strftime("%H:%M"))
            #     logs.info("api-details--> https://s394336720.t.eloqua.com/e/f2?elqFormName=CourseEvents&elqSiteID=394336720&emailAddress="+user.email+"&CourseId="+courseid.display_number_with_default+"&CourseName="+courseid.display_name+"&BannerURL=https://learn.docmode.org"+str(course_image_url)+"&Status=Enrolled&FullName="+displayname.name+"&DisplayDate="+str(courseid.start.date())+"&courseURL="+courseurl+"&EnrollmentID="+str(enrolldata.id)+"&Key=62f74068-90d2-4fd2-bd76-d657fbbbca14&Date="+str(datetime.today()))
            #     syncmail = requests.post("https://s394336720.t.eloqua.com/e/f2?elqFormName=CourseEvents&elqSiteID=394336720&emailAddress="+user.email+"&CourseId="+courseid.display_number_with_default+"&CourseName="+courseid.display_name+"&BannerURL=https://learn.docmode.org"+str(course_image_url)+"&Status=Enrolled&FullName="+displayname.name+"&DisplayDate="+str(courseid.start.date())+"&courseURL="+courseurl+"&EnrollmentID="+str(enrolldata.id)+"&Key=62f74068-90d2-4fd2-bd76-d657fbbbca14&Date="+str(datetime.today()))
            #     logs.info("syncmail--> %s",syncmail.__dict__)
        
        redirect_url = 'https://docvidya.learn.docmode.org/courses/'+course_id+'/courseware'
        
        response = JsonResponse({
            'success': True,
            'redirect_url':redirect_url,
            'status': 200,
            'email':user.email
        })
        #logs.info(u'response2--> %s', response)
        return set_logged_in_cookies(request, response, user)
    except Exception as exc:  # pylint: disable=broad-except
        # AUDIT_LOG.critical("Login failed - Could not create session. Is memcached running?")
        logs.critical("Login failed - Could not create session. Is memcached running?")
        logs.exception(exc)
Exemplo n.º 20
0
def vkonnect__login(request, user, courseid):
    # _track_user_login(user, request)
    logs.info('userid--> %s', request.user)

    try:
        logs.info('userid--> %s', request.user)
        if not request.user.is_authenticated:
            request.session.set_expiry(604800)
            django_login(request,
                         user,
                         backend='django.contrib.auth.backends.ModelBackend')
        else:
            logs.info('userid--> %s', request.user)
            logout(request)
            request.session.set_expiry(604800)
            django_login(request,
                         user,
                         backend='django.contrib.auth.backends.ModelBackend')
        #request.session.set_expiry(604800)
        request.user = user

        logs.info('userid--> %s', request.user)
        user_extra_data = userdetails(user.id)
        course_id = request.data.get('course_id', '')
        course_id = course_id.replace(' ', '+')
        logs.info('course_id %s', course_id)
        course_key = None
        if course_id:

            course_key = CourseKey.from_string(course_id)

            if not CourseEnrollment.is_enrolled(user, course_key):
                logs.info("course enrollment function will be call")
                CourseEnrollment.enroll(user=user,
                                        course_key=course_key,
                                        mode='honor')

        redirect_url = 'https://vkonnecthealth.koa.docmode.org/courses/' + course_id + '/courseware'

        response = JsonResponse({
            'success': True,
            'redirect_url': redirect_url,
            'status': 200,
            'email': user.email
        })
        #logs.info(u'response2--> %s', response)
        return set_logged_in_cookies(request, response, user)
    except Exception as exc:  # pylint: disable=broad-except
        # AUDIT_logs.critical("Login failed - Could not create session. Is memcached running?")
        logs.critical(
            "Login failed - Could not create session. Is memcached running?")
        logs.exception(exc)
Exemplo n.º 21
0
    def test_refresh_jwt_cookies(self):
        def _get_refresh_token_value(response):
            return response.cookies[cookies_api.jwt_cookies.jwt_refresh_cookie_name()].value

        setup_login_oauth_client()
        self._set_use_jwt_cookie_header(self.request)
        response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user)
        self._copy_cookies_to_request(response, self.request)

        new_response = cookies_api.refresh_jwt_cookies(self.request, HttpResponse())
        self._assert_recreate_jwt_from_cookies(new_response, can_recreate=True)
        self.assertNotEqual(
            _get_refresh_token_value(response),
            _get_refresh_token_value(new_response),
        )
Exemplo n.º 22
0
    def test_refresh_jwt_cookies(self):
        def _get_refresh_token_value(response):
            return response.cookies[cookies_api.jwt_cookies.jwt_refresh_cookie_name()].value

        setup_login_oauth_client()
        self._set_use_jwt_cookie_header(self.request)
        response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user)
        self._copy_cookies_to_request(response, self.request)

        new_response = cookies_api.refresh_jwt_cookies(self.request, HttpResponse())
        self._assert_recreate_jwt_from_cookies(new_response, can_recreate=True)
        self.assertNotEqual(
            _get_refresh_token_value(response),
            _get_refresh_token_value(new_response),
        )
Exemplo n.º 23
0
def set_logged_in_cookies(backend=None, user=None, strategy=None, auth_entry=None, current_partial=None,
                          *args, **kwargs):
    """This pipeline step sets the "logged in" cookie for authenticated users.

    Some installations have a marketing site front-end separate from
    edx-platform.  Those installations sometimes display different
    information for logged in versus anonymous users (e.g. a link
    to the student dashboard instead of the login page.)

    Since social auth uses Django's native `login()` method, it bypasses
    our usual login view that sets this cookie.  For this reason, we need
    to set the cookie ourselves within the pipeline.

    The procedure for doing this is a little strange.  On the one hand,
    we need to send a response to the user in order to set the cookie.
    On the other hand, we don't want to drop the user out of the pipeline.

    For this reason, we send a redirect back to the "complete" URL,
    so users immediately re-enter the pipeline.  The redirect response
    contains a header that sets the logged in cookie.

    If the user is not logged in, or the logged in cookie is already set,
    the function returns `None`, indicating that control should pass
    to the next pipeline step.

    """
    if not is_api(auth_entry) and user is not None and user.is_authenticated:
        if not user.has_usable_password():
            msg = "Your account is disabled"
            return JsonResponse(msg, status=403)
        request = strategy.request if strategy else None
        # n.b. for new users, user.is_active may be False at this point; set the cookie anyways.
        if request is not None:
            # Check that the cookie isn't already set.
            # This ensures that we allow the user to continue to the next
            # pipeline step once he/she has the cookie set by this step.
            has_cookie = user_authn_cookies.are_logged_in_cookies_set(request)
            if not has_cookie:
                try:
                    redirect_url = get_complete_url(current_partial.backend)
                except ValueError:
                    # If for some reason we can't get the URL, just skip this step
                    # This may be overly paranoid, but it's far more important that
                    # the user log in successfully than that the cookie is set.
                    pass
                else:
                    response = redirect(redirect_url)
                    return user_authn_cookies.set_logged_in_cookies(request, response, user)
Exemplo n.º 24
0
    def test_delete_and_are_logged_in_cookies_set(self, jwt_cookies_disabled,
                                                  jwk_is_set):
        jwt_private_signing_jwk = settings.JWT_AUTH[
            'JWT_PRIVATE_SIGNING_JWK'] if jwk_is_set else None
        with patch.dict(
                "django.conf.settings.FEATURES",
            {"DISABLE_SET_JWT_COOKIES_FOR_TESTS": jwt_cookies_disabled}):
            with patch.dict(
                    "django.conf.settings.JWT_AUTH",
                {"JWT_PRIVATE_SIGNING_JWK": jwt_private_signing_jwk}):
                setup_login_oauth_client()
                response = cookies_api.set_logged_in_cookies(
                    self.request, HttpResponse(), self.user)
                self._copy_cookies_to_request(response, self.request)
                self.assertTrue(
                    cookies_api.are_logged_in_cookies_set(self.request))

                cookies_api.delete_logged_in_cookies(response)
                self._copy_cookies_to_request(response, self.request)
                self.assertFalse(
                    cookies_api.are_logged_in_cookies_set(self.request))
Exemplo n.º 25
0
    def post(self, request):
        """
        Handler for the POST method to this view.
        """
        # The django login method stores the user's id in request.session[SESSION_KEY] and the
        # path to the user's authentication backend in request.session[BACKEND_SESSION_KEY].
        # The login method assumes the backend path had been previously stored in request.user.backend
        # in the 'authenticate' call.  However, not all authentication providers do so.
        # So we explicitly populate the request.user.backend field here.

        if not hasattr(request.user, 'backend'):
            request.user.backend = self._get_path_of_arbitrary_backend_for_user(request.user)

        if not self._is_grant_password(request.auth):
            raise AuthenticationFailed({
                u'error_code': u'non_supported_token',
                u'developer_message': u'Only support DOT type access token with grant type password. '
            })

        login(request, request.user)  # login generates and stores the user's cookies in the session
        response = HttpResponse(status=204)  # cookies stored in the session are returned with the response
        return set_logged_in_cookies(request, response, request.user)
Exemplo n.º 26
0
def login_user(request):
    """
    AJAX request to log in the user.

    Arguments:
        request (HttpRequest)

    Required params:
        email, password

    Optional params:
        analytics: a JSON-encoded object with additional info to include in the login analytics event. The only
            supported field is "enroll_course_id" to indicate that the user logged in while enrolling in a particular
            course.

    Returns:
        HttpResponse: 200 if successful.
            Ex. {'success': true}
        HttpResponse: 400 if the request failed.
            Ex. {'success': false, 'value': '{'success': false, 'value: 'Email or password is incorrect.'}
        HttpResponse: 403 if successful authentication with a third party provider but does not have a linked account.
            Ex. {'success': false, 'error_code': 'third-party-auth-with-no-linked-account'}

    Example Usage:

        POST /login_ajax
        with POST params `email`, `password`

        200 {'success': true}

    """
    _parse_analytics_param_for_course_id(request)

    third_party_auth_requested = third_party_auth.is_enabled(
    ) and pipeline.running(request)
    first_party_auth_requested = bool(request.POST.get('email')) or bool(
        request.POST.get('password'))
    is_user_third_party_authenticated = False

    set_custom_metric('login_user_course_id', request.POST.get('course_id'))

    try:
        if third_party_auth_requested and not first_party_auth_requested:
            # 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:
                user = _do_third_party_auth(request)
                is_user_third_party_authenticated = True
                set_custom_metric('login_user_tpa_success', True)
            except AuthFailedError as e:
                set_custom_metric('login_user_tpa_success', False)
                set_custom_metric('login_user_tpa_failure_msg', e.value)

                # user successfully authenticated with a third party provider, but has no linked Open edX account
                response_content = e.get_response()
                response_content[
                    'error_code'] = 'third-party-auth-with-no-linked-account'
                return JsonResponse(response_content, status=403)
        else:
            user = _get_user_by_email(request)

        _check_excessive_login_attempts(user)

        possibly_authenticated_user = user

        if not is_user_third_party_authenticated:
            possibly_authenticated_user = _authenticate_first_party(
                request, user, third_party_auth_requested)
            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(user, possibly_authenticated_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 is_user_third_party_authenticated:
            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.
        response = set_logged_in_cookies(request, response,
                                         possibly_authenticated_user)
        set_custom_metric('login_user_auth_failed_error', False)
        set_custom_metric('login_user_response_status', response.status_code)
        set_custom_metric('login_user_redirect_url', redirect_url)
        return response
    except AuthFailedError as error:
        log.exception(error.get_response())
        response = JsonResponse(error.get_response(), status=400)
        set_custom_metric('login_user_auth_failed_error', True)
        set_custom_metric('login_user_response_status', response.status_code)
        return response
Exemplo n.º 27
0
def login_user(request):
    """
    AJAX request to log in the user.
    """
    _parse_analytics_param_for_course_id(request)

    third_party_auth_requested = third_party_auth.is_enabled(
    ) and pipeline.running(request)
    first_party_auth_requested = bool(request.POST.get('email')) or bool(
        request.POST.get('password'))
    is_user_third_party_authenticated = False

    set_custom_metric('login_user_enrollment_action',
                      request.POST.get('enrollment_action'))
    set_custom_metric('login_user_course_id', request.POST.get('course_id'))

    try:
        if third_party_auth_requested and not first_party_auth_requested:
            # 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:
                user = _do_third_party_auth(request)
                is_user_third_party_authenticated = True
                set_custom_metric('login_user_tpa_success', True)
            except AuthFailedError as e:
                set_custom_metric('login_user_tpa_success', False)
                set_custom_metric('login_user_tpa_failure_msg', e.value)

                # user successfully authenticated with a third party provider, but has no linked Open edX account
                response_content = e.get_response()
                response_content[
                    'error_code'] = 'third-party-auth-with-no-linked-account'
                return JsonResponse(response_content, status=403)
        else:
            user = _get_user_by_email(request)

        _check_excessive_login_attempts(user)

        possibly_authenticated_user = user

        if not is_user_third_party_authenticated:
            possibly_authenticated_user = _authenticate_first_party(
                request, 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(user, possibly_authenticated_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 is_user_third_party_authenticated:
            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.
        response = set_logged_in_cookies(request, response,
                                         possibly_authenticated_user)
        set_custom_metric('login_user_auth_failed_error', False)
        set_custom_metric('login_user_response_status', response.status_code)
        return response
    except AuthFailedError as error:
        log.exception(error.get_response())
        # original code returned a 200 status code with status=False for errors. This flag
        # is used for rolling out a transition to using a 400 status code for errors, which
        # is a breaking-change, but will hopefully be a tolerable breaking-change.
        status = 400 if UPDATE_LOGIN_USER_ERROR_STATUS_CODE.is_enabled(
        ) else 200
        response = JsonResponse(error.get_response(), status=status)
        set_custom_metric('login_user_auth_failed_error', True)
        set_custom_metric('login_user_response_status', response.status_code)
        return response
Exemplo n.º 28
0
 def test_set_logged_in_cookies_anonymous_user(self):
     anonymous_user = AnonymousUserFactory()
     response = cookies_api.set_logged_in_cookies(self.request,
                                                  HttpResponse(),
                                                  anonymous_user)
     self._assert_cookies_present(response, [])
Exemplo n.º 29
0
 def test_set_logged_in_cookies_anonymous_user(self):
     anonymous_user = AnonymousUserFactory()
     response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), anonymous_user)
     self._assert_cookies_present(response, [])
Exemplo n.º 30
0
def student_dashboard(request):
    """
    Provides the LMS dashboard view

    TODO: This is lms specific and does not belong in common code.

    Arguments:
        request: The request object.

    Returns:
        The dashboard response.

    """
    user = request.user
    userNewData = UserProfile.objects.filter(user=user)
    if not UserProfile.objects.filter(user=user).exists():
        return redirect(reverse('account_settings'))

    platform_name = configuration_helpers.get_value("platform_name",
                                                    settings.PLATFORM_NAME)

    enable_verified_certificates = configuration_helpers.get_value(
        'ENABLE_VERIFIED_CERTIFICATES',
        settings.FEATURES.get('ENABLE_VERIFIED_CERTIFICATES'))
    display_course_modes_on_dashboard = configuration_helpers.get_value(
        'DISPLAY_COURSE_MODES_ON_DASHBOARD',
        settings.FEATURES.get('DISPLAY_COURSE_MODES_ON_DASHBOARD', True))
    activation_email_support_link = configuration_helpers.get_value(
        'ACTIVATION_EMAIL_SUPPORT_LINK',
        settings.ACTIVATION_EMAIL_SUPPORT_LINK) or settings.SUPPORT_SITE_LINK
    hide_dashboard_courses_until_activated = configuration_helpers.get_value(
        'HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED',
        settings.FEATURES.get('HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED', False))
    empty_dashboard_message = configuration_helpers.get_value(
        'EMPTY_DASHBOARD_MESSAGE', None)

    # Get the org whitelist or the org blacklist for the current site
    site_org_whitelist, site_org_blacklist = get_org_black_and_whitelist_for_site(
    )
    course_enrollments = list(
        get_course_enrollments(user, site_org_whitelist, site_org_blacklist))

    # Get the entitlements for the user and a mapping to all available sessions for that entitlement
    # If an entitlement has no available sessions, pass through a mock course overview object
    (course_entitlements, course_entitlement_available_sessions,
     unfulfilled_entitlement_pseudo_sessions
     ) = get_filtered_course_entitlements(user, site_org_whitelist,
                                          site_org_blacklist)

    # Record how many courses there are so that we can get a better
    # understanding of usage patterns on prod.
    monitoring_utils.accumulate('num_courses', len(course_enrollments))

    # Sort the enrollment pairs by the enrollment date
    course_enrollments.sort(key=lambda x: x.created, reverse=True)

    # Retrieve the course modes for each course
    enrolled_course_ids = [
        enrollment.course_id for enrollment in course_enrollments
    ]
    __, unexpired_course_modes = CourseMode.all_and_unexpired_modes_for_courses(
        enrolled_course_ids)
    course_modes_by_course = {
        course_id: {mode.slug: mode
                    for mode in modes}
        for course_id, modes in iteritems(unexpired_course_modes)
    }

    # Check to see if the student has recently enrolled in a course.
    # If so, display a notification message confirming the enrollment.
    enrollment_message = _create_recent_enrollment_message(
        course_enrollments, course_modes_by_course)
    course_optouts = Optout.objects.filter(user=user).values_list('course_id',
                                                                  flat=True)

    # Display activation message
    activate_account_message = ''
    if not user.is_active:
        activate_account_message = Text(
            _("Check your {email_start}{email}{email_end} inbox for an account activation link from {platform_name}. "
              "If you need help, contact {link_start}{platform_name} Support{link_end}."
              )
        ).format(
            platform_name=platform_name,
            email_start=HTML("<strong>"),
            email_end=HTML("</strong>"),
            email=user.email,
            link_start=HTML(
                "<a target='_blank' href='{activation_email_support_link}'>").
            format(
                activation_email_support_link=activation_email_support_link, ),
            link_end=HTML("</a>"),
        )

    enterprise_message = get_dashboard_consent_notification(
        request, user, course_enrollments)

    recovery_email_message = recovery_email_activation_message = None
    if is_secondary_email_feature_enabled_for_user(user=user):
        try:
            account_recovery_obj = AccountRecovery.objects.get(user=user)
        except AccountRecovery.DoesNotExist:
            recovery_email_message = Text(
                _("Add a recovery email to retain access when single-sign on is not available. "
                  "Go to {link_start}your Account Settings{link_end}.")
            ).format(link_start=HTML(
                "<a target='_blank' href='{account_setting_page}'>").format(
                    account_setting_page=reverse('account_settings'), ),
                     link_end=HTML("</a>"))
        else:
            if not account_recovery_obj.is_active:
                recovery_email_activation_message = Text(
                    _("Recovery email is not activated yet. "
                      "Kindly visit your email and follow the instructions to activate it."
                      ))

    # Disable lookup of Enterprise consent_required_course due to ENT-727
    # Will re-enable after fixing WL-1315
    consent_required_courses = set()
    enterprise_customer_name = None

    # Account activation message
    account_activation_messages = [
        message for message in messages.get_messages(request)
        if 'account-activation' in message.tags
    ]

    # Global staff can see what courses encountered an error on their dashboard
    staff_access = False
    errored_courses = {}
    if has_access(user, 'staff', 'global'):
        # Show any courses that encountered an error on load
        staff_access = True
        errored_courses = modulestore().get_errored_courses()

    show_courseware_links_for = {
        enrollment.course_id: has_access(request.user, 'load',
                                         enrollment.course_overview)
        for enrollment in course_enrollments
    }

    # Find programs associated with course runs being displayed. This information
    # is passed in the template context to allow rendering of program-related
    # information on the dashboard.
    meter = ProgramProgressMeter(request.site,
                                 user,
                                 enrollments=course_enrollments)
    ecommerce_service = EcommerceService()
    inverted_programs = meter.invert_programs()

    urls, programs_data = {}, {}
    bundles_on_dashboard_flag = WaffleFlag(
        WaffleFlagNamespace(name=u'student.experiments'),
        u'bundles_on_dashboard')

    # TODO: Delete this code and the relevant HTML code after testing LEARNER-3072 is complete
    if bundles_on_dashboard_flag.is_enabled(
    ) and inverted_programs and inverted_programs.items():
        if len(course_enrollments) < 4:
            for program in inverted_programs.values():
                try:
                    program_uuid = program[0]['uuid']
                    program_data = get_programs(request.site,
                                                uuid=program_uuid)
                    program_data = ProgramDataExtender(program_data,
                                                       request.user).extend()
                    skus = program_data.get('skus')
                    checkout_page_url = ecommerce_service.get_checkout_page_url(
                        *skus)
                    program_data[
                        'completeProgramURL'] = checkout_page_url + '&bundle=' + program_data.get(
                            'uuid')
                    programs_data[program_uuid] = program_data
                except:  # pylint: disable=bare-except
                    pass

    # Construct a dictionary of course mode information
    # used to render the course list.  We re-use the course modes dict
    # we loaded earlier to avoid hitting the database.
    course_mode_info = {
        enrollment.course_id: complete_course_mode_info(
            enrollment.course_id,
            enrollment,
            modes=course_modes_by_course[enrollment.course_id])
        for enrollment in course_enrollments
    }

    # Determine the per-course verification status
    # This is a dictionary in which the keys are course locators
    # and the values are one of:
    #
    # VERIFY_STATUS_NEED_TO_VERIFY
    # VERIFY_STATUS_SUBMITTED
    # VERIFY_STATUS_APPROVED
    # VERIFY_STATUS_MISSED_DEADLINE
    #
    # Each of which correspond to a particular message to display
    # next to the course on the dashboard.
    #
    # If a course is not included in this dictionary,
    # there is no verification messaging to display.
    verify_status_by_course = check_verify_status_by_course(
        user, course_enrollments)
    cert_statuses = {
        enrollment.course_id: cert_info(request.user,
                                        enrollment.course_overview)
        for enrollment in course_enrollments
    }

    # only show email settings for Mongo course and when bulk email is turned on
    show_email_settings_for = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if (BulkEmailFlag.feature_enabled(enrollment.course_id)))

    # Verification Attempts
    # Used to generate the "you must reverify for course x" banner
    verification_status = IDVerificationService.user_status(user)
    verification_errors = get_verification_error_reasons_for_display(
        verification_status['error'])

    # Gets data for midcourse reverifications, if any are necessary or have failed
    statuses = ["approved", "denied", "pending", "must_reverify"]
    reverifications = reverification_info(statuses)

    block_courses = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if is_course_blocked(
            request,
            CourseRegistrationCode.objects.filter(
                course_id=enrollment.course_id,
                registrationcoderedemption__redeemed_by=request.user),
            enrollment.course_id))

    enrolled_courses_either_paid = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if enrollment.is_paid_course())

    # If there are *any* denied reverifications that have not been toggled off,
    # we'll display the banner
    denied_banner = any(item.display for item in reverifications["denied"])

    # Populate the Order History for the side-bar.
    order_history_list = order_history(user,
                                       course_org_filter=site_org_whitelist,
                                       org_filter_out_set=site_org_blacklist)

    # get list of courses having pre-requisites yet to be completed
    courses_having_prerequisites = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if enrollment.course_overview.pre_requisite_courses)
    courses_requirements_not_met = get_pre_requisite_courses_not_completed(
        user, courses_having_prerequisites)

    if 'notlive' in request.GET:
        redirect_message = _(
            "The course you are looking for does not start until {date}."
        ).format(date=request.GET['notlive'])
    elif 'course_closed' in request.GET:
        redirect_message = _(
            "The course you are looking for is closed for enrollment as of {date}."
        ).format(date=request.GET['course_closed'])
    elif 'access_response_error' in request.GET:
        # This can be populated in a generalized way with fields from access response errors
        redirect_message = request.GET['access_response_error']
    else:
        redirect_message = ''

    valid_verification_statuses = [
        'approved', 'must_reverify', 'pending', 'expired'
    ]
    display_sidebar_on_dashboard = (
        len(order_history_list)
        or (verification_status['status'] in valid_verification_statuses
            and verification_status['should_display']))

    # Filter out any course enrollment course cards that are associated with fulfilled entitlements
    for entitlement in [
            e for e in course_entitlements
            if e.enrollment_course_run is not None
    ]:
        course_enrollments = [
            enr for enr in course_enrollments
            if entitlement.enrollment_course_run.course_id != enr.course_id
        ]

    context = {
        'journal_info':
        get_journals_context(request),  # TODO: Course Listing Plugin required
        'courses':
        get_courses(user),
        'urls':
        urls,
        'programs_data':
        programs_data,
        'enterprise_message':
        enterprise_message,
        'consent_required_courses':
        consent_required_courses,
        'enterprise_customer_name':
        enterprise_customer_name,
        'enrollment_message':
        enrollment_message,
        'redirect_message':
        Text(redirect_message),
        'account_activation_messages':
        account_activation_messages,
        'activate_account_message':
        activate_account_message,
        'course_enrollments':
        course_enrollments,
        'course_entitlements':
        course_entitlements,
        'course_entitlement_available_sessions':
        course_entitlement_available_sessions,
        'unfulfilled_entitlement_pseudo_sessions':
        unfulfilled_entitlement_pseudo_sessions,
        'course_optouts':
        course_optouts,
        'staff_access':
        staff_access,
        'errored_courses':
        errored_courses,
        'show_courseware_links_for':
        show_courseware_links_for,
        'all_course_modes':
        course_mode_info,
        'cert_statuses':
        cert_statuses,
        'credit_statuses':
        _credit_statuses(user, course_enrollments),
        'show_email_settings_for':
        show_email_settings_for,
        'reverifications':
        reverifications,
        'verification_display':
        verification_status['should_display'],
        'verification_status':
        verification_status['status'],
        'verification_status_by_course':
        verify_status_by_course,
        'verification_errors':
        verification_errors,
        'block_courses':
        block_courses,
        'denied_banner':
        denied_banner,
        'billing_email':
        settings.PAYMENT_SUPPORT_EMAIL,
        'user':
        user,
        'logout_url':
        reverse('logout'),
        'platform_name':
        platform_name,
        'enrolled_courses_either_paid':
        enrolled_courses_either_paid,
        'provider_states': [],
        'order_history_list':
        order_history_list,
        'courses_requirements_not_met':
        courses_requirements_not_met,
        'nav_hidden':
        True,
        'inverted_programs':
        inverted_programs,
        'show_program_listing':
        ProgramsApiConfig.is_enabled(),
        'show_journal_listing':
        journals_enabled(),  # TODO: Dashboard Plugin required
        'show_dashboard_tabs':
        True,
        'disable_courseware_js':
        True,
        'display_course_modes_on_dashboard':
        enable_verified_certificates and display_course_modes_on_dashboard,
        'display_sidebar_on_dashboard':
        display_sidebar_on_dashboard,
        'display_sidebar_account_activation_message':
        not (user.is_active or hide_dashboard_courses_until_activated),
        'display_dashboard_courses':
        (user.is_active or not hide_dashboard_courses_until_activated),
        'empty_dashboard_message':
        empty_dashboard_message,
        'recovery_email_message':
        recovery_email_message,
        'recovery_email_activation_message':
        recovery_email_activation_message,
        'data':
        userNewData,
    }

    if ecommerce_service.is_enabled(request.user):
        context.update({
            'use_ecommerce_payment_flow':
            True,
            'ecommerce_payment_page':
            ecommerce_service.payment_page_url(),
        })

    # Gather urls for course card resume buttons.
    resume_button_urls = ['' for entitlement in course_entitlements]
    for url in _get_urls_for_resume_buttons(user, course_enrollments):
        resume_button_urls.append(url)
    # There must be enough urls for dashboard.html. Template creates course
    # cards for "enrollments + entitlements".
    context.update({'resume_button_urls': resume_button_urls})

    response = render_to_response('dashboard.html', context)
    set_logged_in_cookies(request, response, user)
    return response
Exemplo n.º 31
0
    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
Exemplo n.º 32
0
def custom_registration_without_zerobounce(request):
    generated_password = generate_password()

    mandatory_fields = [
        "username",
        "emailid",
        "password",
        "name",
        "phone",
        "user_type",
        "specialization",
        "hcspecialization",
        "pincode",
        "country",
        "state",
        "city",
        "csrfmiddlewaretoken",
    ]
    extradata = {}
    if request.is_ajax():
        if request.method == "POST":
            vfields = request.POST
            for key in vfields:
                if key not in mandatory_fields:
                    extradata[key] = vfields[key]

            uname = request.POST.get("username", "")
            email = request.POST.get("emailid", "")
            password = request.POST.get("password", generated_password)
            if "fname" and "lname" in request.POST:
                fname = request.POST.get("fname", "")
                lname = request.POST.get("lname", "")
                full_name = fname + " " + lname
            else:
                full_name = request.POST.get("name", "")
            phone = request.POST.get("phone", "")
            user_type = "dr"
            specialization = request.POST.get("specialization", "")
            hcspecialization = request.POST.get("hcspecialization", "")
            pincode = request.POST.get("pincode", "")
            country = request.POST.get("country", "")
            state = request.POST.get("state", "")
            city = request.POST.get("city", "")
            is_active = str2bool(request.POST.get("is_active", True))

            try:
                username_validation = User.objects.get(username=uname)
                if username_validation:
                    date = datetime.datetime.now()
                    curr_time = date.strftime("%f")
                    username = uname + "_" + curr_time

            except ObjectDoesNotExist:
                username = uname

            log.info("username--> %s", username)

            form = AccountCreationForm(
                data={
                    "username": username,
                    "email": email,
                    "password": password,
                    "name": full_name,
                },
                tos_required=False,
            )
            restricted = settings.FEATURES.get("RESTRICT_AUTOMATIC_AUTH", True)
            try:
                user, profile, reg = custom_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 JsonResponse(
                    {
                        "status": "403",
                        "msg": "Account creation not allowed either the username is already taken.",
                    }
                )

            # 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()
            user_extrainfo = extrafields(
                phone=phone,
                rcountry=country,
                rstate=state,
                rcity=city,
                rpincode=pincode,
                user_type=user_type,
                specialization_id=specialization,
                hcspecialization_id=hcspecialization,
                user_extra_data=extradata,
                user=user,
            )
            user_extrainfo.save()

            new_user = authenticate_new_user(request, user.username, password)
            django_login(request, new_user)
            request.session.set_expiry(604800)
            # log.info(u'details--> %s,%s,%s', user, profile,reg)

            create_comments_service_user(user)

            create_or_set_user_attribute_created_on_site(user, request.site)
            if "viatris" in str(request.site):
                log.info("newmail12%s", request.site)
                viatris_send_activation_email(user, profile, reg, request.site)
            else:
                log.info("oldmail %s", request.site)
                compose_and_send_activation_email(user, profile, reg)
            messages.success(request, "Kol registration successful.")

            response = JsonResponse(
                {
                    "success": True,
                    "userid": user.id,
                    "mobile": phone,
                    "email": email,
                    "name": full_name,
                    "signupdate": datetime.date.today(),
                    "usertype": "dr",
                    "pincode": pincode,
                    "country": country,
                    "redirect_url": "https://mylan.learn.docmode.org/register?next=/oauth2/authorize/confirm",
                }
            )
            return set_logged_in_cookies(request, response, new_user)
    else:
        messages.success(request, "Welcome to KOL registration page.")

        context = {"errors": "welcome", "csrf": csrf(request)["csrf_token"]}
        return render_to_response("associations/custom_registration.html", context)
def login_and_registration_form(request, initial_mode="login"):
    """Render the combined login/registration form, defaulting to login

    This relies on the JS to asynchronously load the actual form from
    the user_api.

    Keyword Args:
        initial_mode (string): Either "login" or "register".

    """
    # Determine the URL to redirect to following login/registration/third_party_auth
    redirect_to = get_next_url_for_login_page(request)

    # If we're already logged in, redirect to the dashboard
    # Note: If the session is valid, we update all logged_in cookies(in particular JWTs)
    #  since Django's SessionAuthentication middleware auto-updates session cookies but not
    #  the other login-related cookies. See ARCH-282 and ARCHBOM-1718
    if request.user.is_authenticated:
        response = redirect(redirect_to)
        response = set_logged_in_cookies(request, response, request.user)
        return response

    # Retrieve the form descriptions from the user API
    form_descriptions = _get_form_descriptions(request)

    # Our ?next= URL may itself contain a parameter 'tpa_hint=x' that we need to check.
    # If present, we display a login page focused on third-party auth with that provider.
    third_party_auth_hint = None
    if '?' in redirect_to:  # lint-amnesty, pylint: disable=too-many-nested-blocks
        try:
            next_args = urllib.parse.parse_qs(
                urllib.parse.urlparse(redirect_to).query)
            if 'tpa_hint' in next_args:
                provider_id = next_args['tpa_hint'][0]
                tpa_hint_provider = third_party_auth.provider.Registry.get(
                    provider_id=provider_id)
                if tpa_hint_provider:
                    if tpa_hint_provider.skip_hinted_login_dialog:
                        # Forward the user directly to the provider's login URL when the provider is configured
                        # to skip the dialog.
                        if initial_mode == "register":
                            auth_entry = pipeline.AUTH_ENTRY_REGISTER
                        else:
                            auth_entry = pipeline.AUTH_ENTRY_LOGIN
                        return redirect(
                            pipeline.get_login_url(provider_id,
                                                   auth_entry,
                                                   redirect_url=redirect_to))
                    third_party_auth_hint = provider_id
                    initial_mode = "hinted_login"
        except (KeyError, ValueError, IndexError) as ex:
            log.exception("Unknown tpa_hint provider: %s", ex)

    # Redirect to authn MFE if it is enabled or user is not an enterprise user or not coming from a SAML IDP.
    saml_provider = False
    running_pipeline = pipeline.get(request)
    enterprise_customer = enterprise_customer_for_request(request)
    if running_pipeline:
        saml_provider, __ = third_party_auth.utils.is_saml_provider(
            running_pipeline.get('backend'), running_pipeline.get('kwargs'))

    if should_redirect_to_authn_microfrontend(
    ) and not enterprise_customer and not saml_provider:

        # This is to handle a case where a logged-in cookie is not present but the user is authenticated.
        # Note: If we don't handle this learner is redirected to authn MFE and then back to dashboard
        # instead of the desired redirect URL (e.g. finish_auth) resulting in learners not enrolling
        # into the courses.
        if request.user.is_authenticated and redirect_to:
            return redirect(redirect_to)

        query_params = request.GET.urlencode()
        url_path = '/{}{}'.format(initial_mode,
                                  '?' + query_params if query_params else '')
        return redirect(settings.AUTHN_MICROFRONTEND_URL + url_path)

    # Account activation message
    account_activation_messages = [{
        'message': message.message,
        'tags': message.tags
    } for message in messages.get_messages(request)
                                   if 'account-activation' in message.tags]

    account_recovery_messages = [{
        'message': message.message,
        'tags': message.tags
    } for message in messages.get_messages(request)
                                 if 'account-recovery' in message.tags]

    # Otherwise, render the combined login/registration page
    context = {
        'data': {
            'login_redirect_url':
            redirect_to,
            'initial_mode':
            initial_mode,
            'third_party_auth':
            third_party_auth_context(request, redirect_to,
                                     third_party_auth_hint),
            'third_party_auth_hint':
            third_party_auth_hint or '',
            'platform_name':
            configuration_helpers.get_value('PLATFORM_NAME',
                                            settings.PLATFORM_NAME),
            'support_link':
            configuration_helpers.get_value('SUPPORT_SITE_LINK',
                                            settings.SUPPORT_SITE_LINK),
            'password_reset_support_link':
            configuration_helpers.get_value(
                'PASSWORD_RESET_SUPPORT_LINK',
                settings.PASSWORD_RESET_SUPPORT_LINK)
            or settings.SUPPORT_SITE_LINK,
            'account_activation_messages':
            account_activation_messages,
            'account_recovery_messages':
            account_recovery_messages,

            # Include form descriptions retrieved from the user API.
            # We could have the JS client make these requests directly,
            # but we include them in the initial page load to avoid
            # the additional round-trip to the server.
            'login_form_desc':
            json.loads(form_descriptions['login']),
            'registration_form_desc':
            json.loads(form_descriptions['registration']),
            'password_reset_form_desc':
            json.loads(form_descriptions['password_reset']),
            'account_creation_allowed':
            configuration_helpers.get_value(
                'ALLOW_PUBLIC_ACCOUNT_CREATION',
                settings.FEATURES.get('ALLOW_PUBLIC_ACCOUNT_CREATION', True)),
            'is_account_recovery_feature_enabled':
            is_secondary_email_feature_enabled(),
            'is_multiple_user_enterprises_feature_enabled':
            is_multiple_user_enterprises_feature_enabled(),
            'enterprise_slug_login_url':
            get_enterprise_slug_login_url(),
            'is_enterprise_enable':
            enterprise_enabled(),
            'is_require_third_party_auth_enabled':
            is_require_third_party_auth_enabled(),
        },
        'login_redirect_url':
        redirect_to,  # This gets added to the query string of the "Sign In" button in header
        'responsive':
        True,
        'allow_iframing':
        True,
        'disable_courseware_js':
        True,
        'combined_login_and_register':
        True,
        'disable_footer':
        not configuration_helpers.get_value(
            'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER',
            settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER']),
    }

    update_logistration_context_for_enterprise(request, context,
                                               enterprise_customer)

    response = render_to_response('student_account/login_and_register.html',
                                  context)
    handle_enterprise_cookies_for_logistration(request, response, context)

    return response
Exemplo n.º 34
0
 def test_set_logged_in_deprecated_cookies(self):
     response = cookies_api.set_logged_in_cookies(self.request, HttpResponse(), self.user)
     self._assert_cookies_present(response, cookies_api.DEPRECATED_LOGGED_IN_COOKIE_NAMES)
     self._assert_consistent_expires(response)
     self._assert_recreate_jwt_from_cookies(response, can_recreate=False)
Exemplo n.º 35
0
    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
Exemplo n.º 36
0
def student_dashboard(request):
    """
    Provides the LMS dashboard view

    TODO: This is lms specific and does not belong in common code.

    Arguments:
        request: The request object.

    Returns:
        The dashboard response.

    """
    user = request.user
    if not UserProfile.objects.filter(user=user).exists():
        return redirect(reverse('account_settings'))

    platform_name = configuration_helpers.get_value("platform_name", settings.PLATFORM_NAME)

    enable_verified_certificates = configuration_helpers.get_value(
        'ENABLE_VERIFIED_CERTIFICATES',
        settings.FEATURES.get('ENABLE_VERIFIED_CERTIFICATES')
    )
    display_course_modes_on_dashboard = configuration_helpers.get_value(
        'DISPLAY_COURSE_MODES_ON_DASHBOARD',
        settings.FEATURES.get('DISPLAY_COURSE_MODES_ON_DASHBOARD', True)
    )
    activation_email_support_link = configuration_helpers.get_value(
        'ACTIVATION_EMAIL_SUPPORT_LINK', settings.ACTIVATION_EMAIL_SUPPORT_LINK
    ) or settings.SUPPORT_SITE_LINK
    hide_dashboard_courses_until_activated = configuration_helpers.get_value(
        'HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED',
        settings.FEATURES.get('HIDE_DASHBOARD_COURSES_UNTIL_ACTIVATED', False)
    )
    empty_dashboard_message = configuration_helpers.get_value(
        'EMPTY_DASHBOARD_MESSAGE', None
    )

    # Get the org whitelist or the org blacklist for the current site
    site_org_whitelist, site_org_blacklist = get_org_black_and_whitelist_for_site()
    course_enrollments = list(get_course_enrollments(user, site_org_whitelist, site_org_blacklist))

    # Get the entitlements for the user and a mapping to all available sessions for that entitlement
    # If an entitlement has no available sessions, pass through a mock course overview object
    (course_entitlements,
     course_entitlement_available_sessions,
     unfulfilled_entitlement_pseudo_sessions) = get_filtered_course_entitlements(
        user,
        site_org_whitelist,
        site_org_blacklist
    )

    # Record how many courses there are so that we can get a better
    # understanding of usage patterns on prod.
    monitoring_utils.accumulate('num_courses', len(course_enrollments))

    # Sort the enrollment pairs by the enrollment date
    course_enrollments.sort(key=lambda x: x.created, reverse=True)

    # Retrieve the course modes for each course
    enrolled_course_ids = [enrollment.course_id for enrollment in course_enrollments]
    __, unexpired_course_modes = CourseMode.all_and_unexpired_modes_for_courses(enrolled_course_ids)
    course_modes_by_course = {
        course_id: {
            mode.slug: mode
            for mode in modes
        }
        for course_id, modes in iteritems(unexpired_course_modes)
    }

    # Check to see if the student has recently enrolled in a course.
    # If so, display a notification message confirming the enrollment.
    enrollment_message = _create_recent_enrollment_message(
        course_enrollments, course_modes_by_course
    )
    course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True)

    # Display activation message
    activate_account_message = ''
    if not user.is_active:
        activate_account_message = Text(_(
            "Check your {email_start}{email}{email_end} inbox for an account activation link from {platform_name}. "
            "If you need help, contact {link_start}{platform_name} Support{link_end}."
        )).format(
            platform_name=platform_name,
            email_start=HTML("<strong>"),
            email_end=HTML("</strong>"),
            email=user.email,
            link_start=HTML("<a target='_blank' href='{activation_email_support_link}'>").format(
                activation_email_support_link=activation_email_support_link,
            ),
            link_end=HTML("</a>"),
        )

    enterprise_message = get_dashboard_consent_notification(request, user, course_enrollments)

    recovery_email_message = recovery_email_activation_message = None
    if is_secondary_email_feature_enabled_for_user(user=user):
        try:
            account_recovery_obj = AccountRecovery.objects.get(user=user)
        except AccountRecovery.DoesNotExist:
            recovery_email_message = Text(
                _(
                    "Add a recovery email to retain access when single-sign on is not available. "
                    "Go to {link_start}your Account Settings{link_end}.")
            ).format(
                link_start=HTML("<a href='{account_setting_page}'>").format(
                    account_setting_page=reverse('account_settings'),
                ),
                link_end=HTML("</a>")
            )
        else:
            if not account_recovery_obj.is_active:
                recovery_email_activation_message = Text(
                    _(
                        "Recovery email is not activated yet. "
                        "Kindly visit your email and follow the instructions to activate it."
                    )
                )

    # Disable lookup of Enterprise consent_required_course due to ENT-727
    # Will re-enable after fixing WL-1315
    consent_required_courses = set()
    enterprise_customer_name = None

    # Account activation message
    account_activation_messages = [
        message for message in messages.get_messages(request) if 'account-activation' in message.tags
    ]

    # Global staff can see what courses encountered an error on their dashboard
    staff_access = False
    errored_courses = {}
    if has_access(user, 'staff', 'global'):
        # Show any courses that encountered an error on load
        staff_access = True
        errored_courses = modulestore().get_errored_courses()

    show_courseware_links_for = {
        enrollment.course_id: has_access(request.user, 'load', enrollment.course_overview)
        for enrollment in course_enrollments
    }

    # Find programs associated with course runs being displayed. This information
    # is passed in the template context to allow rendering of program-related
    # information on the dashboard.
    meter = ProgramProgressMeter(request.site, user, enrollments=course_enrollments)
    ecommerce_service = EcommerceService()
    inverted_programs = meter.invert_programs()

    urls, programs_data = {}, {}
    bundles_on_dashboard_flag = WaffleFlag(experiments_namespace, u'bundles_on_dashboard')

    # TODO: Delete this code and the relevant HTML code after testing LEARNER-3072 is complete
    if bundles_on_dashboard_flag.is_enabled() and inverted_programs and list(inverted_programs.items()):
        if len(course_enrollments) < 4:
            for program in inverted_programs.values():
                try:
                    program_uuid = program[0]['uuid']
                    program_data = get_programs(uuid=program_uuid)
                    program_data = ProgramDataExtender(program_data, request.user).extend()
                    skus = program_data.get('skus')
                    checkout_page_url = ecommerce_service.get_checkout_page_url(*skus)
                    program_data['completeProgramURL'] = checkout_page_url + '&bundle=' + program_data.get('uuid')
                    programs_data[program_uuid] = program_data
                except:  # pylint: disable=bare-except
                    pass

    # Construct a dictionary of course mode information
    # used to render the course list.  We re-use the course modes dict
    # we loaded earlier to avoid hitting the database.
    course_mode_info = {
        enrollment.course_id: complete_course_mode_info(
            enrollment.course_id, enrollment,
            modes=course_modes_by_course[enrollment.course_id]
        )
        for enrollment in course_enrollments
    }

    # Determine the per-course verification status
    # This is a dictionary in which the keys are course locators
    # and the values are one of:
    #
    # VERIFY_STATUS_NEED_TO_VERIFY
    # VERIFY_STATUS_SUBMITTED
    # VERIFY_STATUS_APPROVED
    # VERIFY_STATUS_MISSED_DEADLINE
    #
    # Each of which correspond to a particular message to display
    # next to the course on the dashboard.
    #
    # If a course is not included in this dictionary,
    # there is no verification messaging to display.
    verify_status_by_course = check_verify_status_by_course(user, course_enrollments)
    cert_statuses = {
        enrollment.course_id: cert_info(request.user, enrollment.course_overview)
        for enrollment in course_enrollments
    }

    # only show email settings for Mongo course and when bulk email is turned on
    show_email_settings_for = frozenset(
        enrollment.course_id for enrollment in course_enrollments if (
            is_bulk_email_feature_enabled(enrollment.course_id)
        )
    )

    # Verification Attempts
    # Used to generate the "you must reverify for course x" banner
    verification_status = IDVerificationService.user_status(user)
    verification_errors = get_verification_error_reasons_for_display(verification_status['error'])

    # Gets data for midcourse reverifications, if any are necessary or have failed
    statuses = ["approved", "denied", "pending", "must_reverify"]
    reverifications = reverification_info(statuses)

    block_courses = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if is_course_blocked(
            request,
            CourseRegistrationCode.objects.filter(
                course_id=enrollment.course_id,
                registrationcoderedemption__redeemed_by=request.user
            ),
            enrollment.course_id
        )
    )

    enrolled_courses_either_paid = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if enrollment.is_paid_course()
    )

    # If there are *any* denied reverifications that have not been toggled off,
    # we'll display the banner
    denied_banner = any(item.display for item in reverifications["denied"])

    # Populate the Order History for the side-bar.
    order_history_list = order_history(
        user,
        course_org_filter=site_org_whitelist,
        org_filter_out_set=site_org_blacklist
    )

    # get list of courses having pre-requisites yet to be completed
    courses_having_prerequisites = frozenset(
        enrollment.course_id for enrollment in course_enrollments
        if enrollment.course_overview.pre_requisite_courses
    )
    courses_requirements_not_met = get_pre_requisite_courses_not_completed(user, courses_having_prerequisites)

    if 'notlive' in request.GET:
        redirect_message = _("The course you are looking for does not start until {date}.").format(
            date=request.GET['notlive']
        )
    elif 'course_closed' in request.GET:
        redirect_message = _("The course you are looking for is closed for enrollment as of {date}.").format(
            date=request.GET['course_closed']
        )
    elif 'access_response_error' in request.GET:
        # This can be populated in a generalized way with fields from access response errors
        redirect_message = request.GET['access_response_error']
    else:
        redirect_message = ''

    valid_verification_statuses = ['approved', 'must_reverify', 'pending', 'expired']
    display_sidebar_on_dashboard = (len(order_history_list) or
                                    (verification_status['status'] in valid_verification_statuses and
                                    verification_status['should_display']))

    # Filter out any course enrollment course cards that are associated with fulfilled entitlements
    for entitlement in [e for e in course_entitlements if e.enrollment_course_run is not None]:
        course_enrollments = [
            enr for enr in course_enrollments if entitlement.enrollment_course_run.course_id != enr.course_id
        ]

    context = {
        'urls': urls,
        'programs_data': programs_data,
        'enterprise_message': enterprise_message,
        'consent_required_courses': consent_required_courses,
        'enterprise_customer_name': enterprise_customer_name,
        'enrollment_message': enrollment_message,
        'redirect_message': Text(redirect_message),
        'account_activation_messages': account_activation_messages,
        'activate_account_message': activate_account_message,
        'course_enrollments': course_enrollments,
        'course_entitlements': course_entitlements,
        'course_entitlement_available_sessions': course_entitlement_available_sessions,
        'unfulfilled_entitlement_pseudo_sessions': unfulfilled_entitlement_pseudo_sessions,
        'course_optouts': course_optouts,
        'staff_access': staff_access,
        'errored_courses': errored_courses,
        'show_courseware_links_for': show_courseware_links_for,
        'all_course_modes': course_mode_info,
        'cert_statuses': cert_statuses,
        'credit_statuses': _credit_statuses(user, course_enrollments),
        'show_email_settings_for': show_email_settings_for,
        'reverifications': reverifications,
        'verification_display': verification_status['should_display'],
        'verification_status': verification_status['status'],
        'verification_status_by_course': verify_status_by_course,
        'verification_errors': verification_errors,
        'block_courses': block_courses,
        'denied_banner': denied_banner,
        'billing_email': settings.PAYMENT_SUPPORT_EMAIL,
        'user': user,
        'logout_url': reverse('logout'),
        'platform_name': platform_name,
        'enrolled_courses_either_paid': enrolled_courses_either_paid,
        'provider_states': [],
        'order_history_list': order_history_list,
        'courses_requirements_not_met': courses_requirements_not_met,
        'nav_hidden': True,
        'inverted_programs': inverted_programs,
        'show_program_listing': ProgramsApiConfig.is_enabled(),
        'show_journal_listing': journals_enabled(),  # TODO: Dashboard Plugin required
        'show_dashboard_tabs': True,
        'disable_courseware_js': True,
        'display_course_modes_on_dashboard': enable_verified_certificates and display_course_modes_on_dashboard,
        'display_sidebar_on_dashboard': display_sidebar_on_dashboard,
        'display_sidebar_account_activation_message': not(user.is_active or hide_dashboard_courses_until_activated),
        'display_dashboard_courses': (user.is_active or not hide_dashboard_courses_until_activated),
        'empty_dashboard_message': empty_dashboard_message,
        'recovery_email_message': recovery_email_message,
        'recovery_email_activation_message': recovery_email_activation_message,
        # TODO START: Clean up REVEM-205 & REVEM-204.
        # The below context is for experiments in dashboard_metadata
        'course_prices': get_experiment_dashboard_metadata_context(course_enrollments) if DASHBOARD_METADATA_FLAG.is_enabled() else None,
        # TODO END: Clean up REVEM-205 & REVEM-204.
        # TODO START: clean up as part of REVEM-199 (START)
        'course_info': get_dashboard_course_info(user, course_enrollments),
        # TODO START: clean up as part of REVEM-199 (END)
    }

    if ecommerce_service.is_enabled(request.user):
        context.update({
            'use_ecommerce_payment_flow': True,
            'ecommerce_payment_page': ecommerce_service.payment_page_url(),
        })

    # Gather urls for course card resume buttons.
    resume_button_urls = ['' for entitlement in course_entitlements]
    for url in get_resume_urls_for_enrollments(user, course_enrollments).values():
        resume_button_urls.append(url)
    # There must be enough urls for dashboard.html. Template creates course
    # cards for "enrollments + entitlements".
    context.update({
        'resume_button_urls': resume_button_urls
    })

    response = render_to_response('dashboard.html', context)
    set_logged_in_cookies(request, response, user)
    return response
Exemplo n.º 37
0
def login_user(request, api_version='v1'):
    """
    AJAX request to log in the user.

    Arguments:
        request (HttpRequest)

    Required params:
        email, password

    Optional params:
        analytics: a JSON-encoded object with additional info to include in the login analytics event. The only
            supported field is "enroll_course_id" to indicate that the user logged in while enrolling in a particular
            course.

    Returns:
        HttpResponse: 200 if successful.
            Ex. {'success': true}
        HttpResponse: 400 if the request failed.
            Ex. {'success': false, 'value': '{'success': false, 'value: 'Email or password is incorrect.'}
        HttpResponse: 403 if successful authentication with a third party provider but does not have a linked account.
            Ex. {'success': false, 'error_code': 'third-party-auth-with-no-linked-account'}

    Example Usage:

        POST /login_ajax
        with POST params `email`, `password`

        200 {'success': true}

    """
    _parse_analytics_param_for_course_id(request)

    third_party_auth_requested = third_party_auth.is_enabled(
    ) and pipeline.running(request)
    first_party_auth_requested = bool(request.POST.get('email')) or bool(
        request.POST.get('password'))
    is_user_third_party_authenticated = False

    set_custom_attribute('login_user_course_id', request.POST.get('course_id'))

    if is_require_third_party_auth_enabled(
    ) and not third_party_auth_requested:
        return HttpResponseForbidden(
            "Third party authentication is required to login. Username and password were received instead."
        )
    possibly_authenticated_user = None
    try:
        if third_party_auth_requested and not first_party_auth_requested:
            # 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:
                user = _do_third_party_auth(request)
                is_user_third_party_authenticated = True
                set_custom_attribute('login_user_tpa_success', True)
            except AuthFailedError as e:
                set_custom_attribute('login_user_tpa_success', False)
                set_custom_attribute('login_user_tpa_failure_msg', e.value)
                if e.error_code:
                    set_custom_attribute('login_error_code', e.error_code)

                # user successfully authenticated with a third party provider, but has no linked Open edX account
                response_content = e.get_response()
                return JsonResponse(response_content, status=403)
        else:
            user = _get_user_by_email_or_username(request, api_version)

        _check_excessive_login_attempts(user)

        possibly_authenticated_user = user

        if not is_user_third_party_authenticated:
            possibly_authenticated_user = _authenticate_first_party(
                request, user, third_party_auth_requested)
            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)
                check_pwned_password_and_send_track_event.delay(
                    user.id, request.POST.get('password'), user.is_staff)

        if possibly_authenticated_user is None or not (
                possibly_authenticated_user.is_active
                or settings.MARKETING_EMAILS_OPT_IN):
            _handle_failed_authentication(user, possibly_authenticated_user)

        _handle_successful_authentication_and_login(
            possibly_authenticated_user, request)

        # The AJAX method calling should know the default destination upon success
        redirect_url, finish_auth_url = None, ''

        if third_party_auth_requested:
            running_pipeline = pipeline.get(request)
            finish_auth_url = pipeline.get_complete_url(
                backend_name=running_pipeline['backend'])

        if is_user_third_party_authenticated:
            redirect_url = finish_auth_url
        elif should_redirect_to_authn_microfrontend():
            next_url, root_url = get_next_url_for_login_page(request,
                                                             include_host=True)
            redirect_url = get_redirect_url_with_host(
                root_url,
                enterprise_selection_page(request, possibly_authenticated_user,
                                          finish_auth_url or next_url))

        response = JsonResponse({
            'success': True,
            'redirect_url': redirect_url,
        })

        # Ensure that the external marketing site can
        # detect that the user is logged in.
        response = set_logged_in_cookies(request, response,
                                         possibly_authenticated_user)
        set_custom_attribute('login_user_auth_failed_error', False)
        set_custom_attribute('login_user_response_status',
                             response.status_code)
        set_custom_attribute('login_user_redirect_url', redirect_url)
        mark_user_change_as_expected(response, user.id)
        return response
    except AuthFailedError as error:
        response_content = error.get_response()
        log.exception(response_content)

        error_code = response_content.get('error_code')
        if error_code:
            set_custom_attribute('login_error_code', error_code)
        email_or_username_key = 'email' if api_version == API_V1 else 'email_or_username'
        email_or_username = request.POST.get(email_or_username_key, None)
        email_or_username = possibly_authenticated_user.email \
            if possibly_authenticated_user else email_or_username
        response_content['email'] = email_or_username
        response = JsonResponse(response_content, status=400)
        set_custom_attribute('login_user_auth_failed_error', True)
        set_custom_attribute('login_user_response_status',
                             response.status_code)
        return response