def test_unsafe_next(self):
     """ Test unsafe next parameter """
     unsafe_url = "https://www.amazon.com"
     with LogCapture(LOGGER_NAME, level=logging.ERROR) as logger:
         req = self.request.get(reverse("login") + "?next={url}".format(url=unsafe_url))
         get_next_url_for_login_page(req)
         logger.check(
             (LOGGER_NAME, "ERROR", u"Unsafe redirect parameter detected: u'{url}'".format(url=unsafe_url))
         )
示例#2
0
 def test_unsafe_next(self, unsafe_url, http_accept, user_agent, expected_log):
     """ Test unsafe next parameter """
     with LogCapture(LOGGER_NAME, level=logging.WARNING) as logger:
         req = self.request.get(reverse("login") + "?next={url}".format(url=unsafe_url))
         req.META["HTTP_ACCEPT"] = http_accept  # pylint: disable=no-member
         req.META["HTTP_USER_AGENT"] = user_agent  # pylint: disable=no-member
         get_next_url_for_login_page(req)
         logger.check(
             (LOGGER_NAME, "WARNING", expected_log)
         )
示例#3
0
 def test_next_failures(self, log_level, log_name, unsafe_url, http_accept,
                        user_agent, expected_log):
     """ Test unsafe next parameter """
     with LogCapture(LOGGER_NAME, level=log_level) as logger:
         req = self.request.get(settings.LOGIN_URL +
                                "?next={url}".format(url=unsafe_url))
         req.META["HTTP_ACCEPT"] = http_accept
         req.META["HTTP_USER_AGENT"] = user_agent
         get_next_url_for_login_page(req)
         logger.check((LOGGER_NAME, log_name, expected_log))
示例#4
0
 def test_next_failures(self, log_level, log_name, unsafe_url, http_accept,
                        user_agent, expected_log):
     """ Test unsafe next parameter """
     with LogCapture(LOGGER_NAME, level=log_level) as logger:
         req = self.request.get(
             reverse("login") + "?next={url}".format(url=unsafe_url))
         req.META["HTTP_ACCEPT"] = http_accept  # pylint: disable=no-member
         req.META["HTTP_USER_AGENT"] = user_agent  # pylint: disable=no-member
         get_next_url_for_login_page(req)
         logger.check((LOGGER_NAME, log_name, expected_log))
示例#5
0
 def test_unsafe_next(self):
     """ Test unsafe next parameter """
     unsafe_url = "https://www.amazon.com"
     with LogCapture(LOGGER_NAME, level=logging.ERROR) as logger:
         req = self.request.get(
             reverse("login") + "?next={url}".format(url=unsafe_url))
         get_next_url_for_login_page(req)
         logger.check(
             (LOGGER_NAME, "ERROR",
              u"Unsafe redirect parameter detected: u'{url}'".format(
                  url=unsafe_url)))
示例#6
0
 def test_unsafe_next(self, unsafe_url, http_accept):
     """ Test unsafe next parameter """
     with LogCapture(LOGGER_NAME, level=logging.WARNING) as logger:
         req = self.request.get(
             reverse("login") + "?next={url}".format(url=unsafe_url))
         req.META["HTTP_ACCEPT"] = http_accept  # pylint: disable=no-member
         get_next_url_for_login_page(req)
         logger.check((
             LOGGER_NAME, "WARNING",
             u"Unsafe redirect parameter detected after login page: u'{url}'"
             .format(url=unsafe_url)))
示例#7
0
 def test_safe_next(self):
     """ Test safe next parameter """
     req = self.request.get(
         reverse("login") + "?next={url}".format(url="/dashboard"))
     req.META["HTTP_ACCEPT"] = "text/html"  # pylint: disable=no-member
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, u'/dashboard')
示例#8
0
文件: views.py 项目: saadow123/1
    def get(self, request, *args, **kwargs):
        """
        Return either a redirect to the login page of an identity provider that
        corresponds to the provider_slug keyword argument or a 404 if the
        provider_slug does not correspond to an identity provider.

        Args:
            request (HttpRequest)

        Keyword Args:
            provider_slug (str): a slug corresponding to a configured identity provider

        Returns:
            HttpResponse: 302 to a provider's login url if the provider_slug kwarg matches an identity provider
            HttpResponse: 404 if the provider_slug kwarg does not match an identity provider
        """
        # this gets the url to redirect to after login/registration/third_party_auth
        # it also handles checking the safety of the redirect url (next query parameter)
        # it checks against settings.LOGIN_REDIRECT_WHITELIST, so be sure to add the url
        # to this setting
        next_destination_url = get_next_url_for_login_page(request)

        try:
            url = pipeline.get_login_url(kwargs['provider_slug'],
                                         pipeline.AUTH_ENTRY_LOGIN,
                                         next_destination_url)
            return redirect(url)
        except ValueError:
            return HttpResponseNotFound()
示例#9
0
def signin_user(request):
    """Deprecated. To be replaced by :class:`student_account.views.login_and_registration_form`."""
    external_auth_response = external_auth_login(request)
    if external_auth_response is not None:
        return external_auth_response
    # Determine the URL to redirect to following login:
    redirect_to = get_next_url_for_login_page(request)
    if request.user.is_authenticated:
        return redirect(redirect_to)

    third_party_auth_error = None
    for msg in messages.get_messages(request):
        if msg.extra_tags.split()[0] == "social-auth":
            # msg may or may not be translated. Try translating [again] in case we are able to:
            third_party_auth_error = _(text_type(msg))  # pylint: disable=translation-of-non-string
            break

    context = {
        'login_redirect_url': redirect_to,  # This gets added to the query string of the "Sign In" button in the header
        # Bool injected into JS to submit form if we're inside a running third-
        # party auth pipeline; distinct from the actual instance of the running
        # pipeline, if any.
        'pipeline_running': 'true' if pipeline.running(request) else 'false',
        'pipeline_url': auth_pipeline_urls(pipeline.AUTH_ENTRY_LOGIN, redirect_url=redirect_to),
        'platform_name': configuration_helpers.get_value(
            'platform_name',
            settings.PLATFORM_NAME
        ),
        'third_party_auth_error': third_party_auth_error
    }

    return render_to_response('login.html', context)
示例#10
0
def openid_login_complete(request,
                          redirect_field_name=REDIRECT_FIELD_NAME,  # pylint: disable=unused-argument
                          render_failure=None):
    """Complete the openid login process"""

    render_failure = (render_failure or default_render_failure)

    openid_response = openid_views.parse_openid_response(request)
    if not openid_response:
        return render_failure(request,
                              'This is an OpenID relying party endpoint.')

    if openid_response.status == SUCCESS:
        external_id = openid_response.identity_url
        oid_backend = openid_auth.OpenIDBackend()
        details = oid_backend._extract_user_details(openid_response)  # pylint: disable=protected-access

        log.debug('openid success, details=%s', details)

        url = getattr(settings, 'OPENID_SSO_SERVER_URL', None)
        external_domain = "{0}{1}".format(OPENID_DOMAIN_PREFIX, url)
        fullname = '%s %s' % (details.get('first_name', ''),
                              details.get('last_name', ''))

        return _external_login_or_signup(
            request,
            external_id,
            external_domain,
            details,
            details.get('email', ''),
            fullname,
            retfun=functools.partial(redirect, get_next_url_for_login_page(request)),
        )

    return render_failure(request, 'Openid failure')
示例#11
0
 def validate_login():
     req = self.request.get(
         reverse("login") + "?next={url}".format(url=next_url))
     req.META["HTTP_ACCEPT"] = "text/html"  # pylint: disable=no-member
     self._add_session(req)
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, expected_url)
示例#12
0
def openid_login_complete(request,
                          redirect_field_name=REDIRECT_FIELD_NAME,
                          render_failure=None):
    """Complete the openid login process"""

    render_failure = (render_failure or default_render_failure)

    openid_response = openid_views.parse_openid_response(request)
    if not openid_response:
        return render_failure(request,
                              'This is an OpenID relying party endpoint.')

    if openid_response.status == SUCCESS:
        external_id = openid_response.identity_url
        oid_backend = openid_auth.OpenIDBackend()
        details = oid_backend._extract_user_details(openid_response)

        log.debug('openid success, details=%s', details)

        url = getattr(settings, 'OPENID_SSO_SERVER_URL', None)
        external_domain = "{0}{1}".format(OPENID_DOMAIN_PREFIX, url)
        fullname = '%s %s' % (details.get('first_name', ''),
                              details.get('last_name', ''))

        return _external_login_or_signup(
            request,
            external_id,
            external_domain,
            details,
            details.get('email', ''),
            fullname,
            retfun=functools.partial(redirect, get_next_url_for_login_page(request)),
        )

    return render_failure(request, 'Openid failure')
示例#13
0
 def test_safe_next(self, next_url, host):
     """ Test safe next parameter """
     req = self.request.get(settings.LOGIN_URL +
                            "?next={url}".format(url=next_url),
                            HTTP_HOST=host)
     req.META["HTTP_ACCEPT"] = "text/html"  # pylint: disable=no-member
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, next_url)
示例#14
0
 def test_safe_next(self, next_url, http_accept, host):
     """ Test safe next parameter """
     req = self.request.get(settings.LOGIN_URL +
                            "?next={url}".format(url=next_url),
                            HTTP_HOST=host)
     req.META["HTTP_ACCEPT"] = http_accept
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, next_url)
示例#15
0
 def test_safe_next(self, url, host, expected_url):
     """ Test safe next parameter """
     req = self.request.get(reverse("login") +
                            "?next={url}".format(url=url),
                            HTTP_HOST=host)
     req.META["HTTP_ACCEPT"] = "text/html"  # pylint: disable=no-member
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, expected_url)
示例#16
0
    def dispatch(self, request, *args, **kwargs):
        """
        Override dispatch to perform permission checks.
        """
        if not self.check_permission():
            return redirect('/login?next=' +
                            get_next_url_for_login_page(request))

        return super(BaseViewMixin, self).dispatch(request, *args, **kwargs)
示例#17
0
def register_user(request, extra_context=None):
    """
    Deprecated. To be replaced by :class:`user_authn.views.login_form.login_and_registration_form`.
    """
    # Determine the URL to redirect to following login:
    redirect_to = get_next_url_for_login_page(request)
    if request.user.is_authenticated:
        return redirect(redirect_to)

    external_auth_response = external_auth_register(request)
    if external_auth_response is not None:
        return external_auth_response

    context = {
        'login_redirect_url':
        redirect_to,  # This gets added to the query string of the "Sign In" button in the header
        'email':
        '',
        'name':
        '',
        'running_pipeline':
        None,
        'pipeline_urls':
        auth_pipeline_urls(pipeline.AUTH_ENTRY_REGISTER,
                           redirect_url=redirect_to),
        'platform_name':
        configuration_helpers.get_value('platform_name',
                                        settings.PLATFORM_NAME),
        'selected_provider':
        '',
        'username':
        '',
    }

    if extra_context is not None:
        context.update(extra_context)

    if context.get("extauth_domain",
                   '').startswith(settings.SHIBBOLETH_DOMAIN_PREFIX):
        return render_to_response('register-shib.html', context)

    # If third-party auth is enabled, prepopulate the form with data from the
    # selected provider.
    if third_party_auth.is_enabled() and pipeline.running(request):
        running_pipeline = pipeline.get(request)
        current_provider = provider.Registry.get_from_pipeline(
            running_pipeline)
        if current_provider is not None:
            overrides = current_provider.get_register_form_data(
                running_pipeline.get('kwargs'))
            overrides['running_pipeline'] = running_pipeline
            overrides['selected_provider'] = current_provider.name
            context.update(overrides)

    return render_to_response('register.html', context)
示例#18
0
def shib_login(request):
    """
        Uses Apache's REMOTE_USER environment variable as the external id.
        This in turn typically uses EduPersonPrincipalName
        http://www.incommonfederation.org/attributesummary.html#eduPersonPrincipal
        but the configuration is in the shibboleth software.
    """
    shib_error_msg = _(
        dedent("""
        Your university identity server did not return your ID information to us.
        Please try logging in again.  (You may need to restart your browser.)
        """))

    if not request.META.get('REMOTE_USER'):
        log.error(u"SHIB: no REMOTE_USER found in request.META")
        return default_render_failure(request, shib_error_msg)
    elif not request.META.get('Shib-Identity-Provider'):
        log.error(u"SHIB: no Shib-Identity-Provider in request.META")
        return default_render_failure(request, shib_error_msg)
    else:
        # If we get here, the user has authenticated properly
        shib = {
            attr: request.META.get(attr, '').decode('utf-8')
            for attr in [
                'REMOTE_USER', 'givenName', 'sn', 'mail',
                'Shib-Identity-Provider', 'displayName'
            ]
        }

        # Clean up first name, last name, and email address
        # TODO: Make this less hardcoded re: format, but split will work
        # even if ";" is not present, since we are accessing 1st element
        shib['sn'] = shib['sn'].split(";")[0].strip().capitalize()
        shib['givenName'] = shib['givenName'].split(
            ";")[0].strip().capitalize()

    # TODO: should we be logging creds here, at info level?
    log.info(u"SHIB creds returned: %r", shib)

    fullname = shib['displayName'] if shib['displayName'] else u'%s %s' % (
        shib['givenName'], shib['sn'])

    redirect_to = get_next_url_for_login_page(request)
    retfun = functools.partial(_safe_postlogin_redirect, redirect_to,
                               request.get_host())

    return _external_login_or_signup(request,
                                     external_id=shib['REMOTE_USER'],
                                     external_domain=SHIBBOLETH_DOMAIN_PREFIX +
                                     shib['Shib-Identity-Provider'],
                                     credentials=shib,
                                     email=shib['mail'],
                                     fullname=fullname,
                                     retfun=retfun)
示例#19
0
def shib_login(request):
    """
        Uses Apache's REMOTE_USER environment variable as the external id.
        This in turn typically uses EduPersonPrincipalName
        http://www.incommonfederation.org/attributesummary.html#eduPersonPrincipal
        but the configuration is in the shibboleth software.
    """
    shib_error_msg = _(
        dedent(
            """
        Your university identity server did not return your ID information to us.
        Please try logging in again.  (You may need to restart your browser.)
        """
        )
    )

    if not request.META.get("REMOTE_USER"):
        log.error(u"SHIB: no REMOTE_USER found in request.META")
        return default_render_failure(request, shib_error_msg)
    elif not request.META.get("Shib-Identity-Provider"):
        log.error(u"SHIB: no Shib-Identity-Provider in request.META")
        return default_render_failure(request, shib_error_msg)
    else:
        # If we get here, the user has authenticated properly
        shib = {
            attr: request.META.get(attr, "").decode("utf-8")
            for attr in ["REMOTE_USER", "givenName", "sn", "mail", "Shib-Identity-Provider", "displayName"]
        }

        # Clean up first name, last name, and email address
        # TODO: Make this less hardcoded re: format, but split will work
        # even if ";" is not present, since we are accessing 1st element
        shib["sn"] = shib["sn"].split(";")[0].strip().capitalize()
        shib["givenName"] = shib["givenName"].split(";")[0].strip().capitalize()

    # TODO: should we be logging creds here, at info level?
    log.info(u"SHIB creds returned: %r", shib)

    fullname = shib["displayName"] if shib["displayName"] else u"%s %s" % (shib["givenName"], shib["sn"])

    redirect_to = get_next_url_for_login_page(request)
    retfun = functools.partial(_safe_postlogin_redirect, redirect_to, request.get_host())

    return _external_login_or_signup(
        request,
        external_id=shib["REMOTE_USER"],
        external_domain=SHIBBOLETH_DOMAIN_PREFIX + shib["Shib-Identity-Provider"],
        credentials=shib,
        email=shib["mail"],
        fullname=fullname,
        retfun=retfun,
    )
示例#20
0
文件: views.py 项目: JudyFox/edXMOOC
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
    if request.user.is_authenticated():
        return redirect(redirect_to)

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

    # If this is a microsite, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    if microsite.is_request_in_microsite():
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # Otherwise, render the combined login/registration page
    context = {
        'login_redirect_url': redirect_to,  # This gets added to the query string of the "Sign In" button in the header
        'disable_courseware_js': True,
        'initial_mode': initial_mode,
        'third_party_auth': json.dumps(_third_party_auth_context(request, redirect_to)),
        'platform_name': settings.PLATFORM_NAME,
        'responsive': True,

        # 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': form_descriptions['login'],
        'registration_form_desc': form_descriptions['registration'],
        'password_reset_form_desc': form_descriptions['password_reset'],
    }

    return render_to_response('student_account/login_and_register.html', context)
示例#21
0
def get_provider_login_url(request, provider_id, redirect_url=None):
    """
    Return the given provider's login URL.

    This method is here to avoid the importing of pipeline and student app in enterprise.
    """

    provider_login_url = third_party_auth.pipeline.get_login_url(
        provider_id,
        third_party_auth.pipeline.AUTH_ENTRY_LOGIN,
        redirect_url=redirect_url if redirect_url else get_next_url_for_login_page(request)
    )
    return provider_login_url
示例#22
0
 def validate_login():
     """
     Assert that get_next_url_for_login_page returns as expected.
     """
     if method == 'GET':
         req = self.request.get(settings.LOGIN_URL +
                                "?next={url}".format(url=next_url))
     elif method == 'POST':
         req = self.request.post(settings.LOGIN_URL, {'next': next_url})
     req.META["HTTP_ACCEPT"] = "text/html"
     self._add_session(req)
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, expected_url)
示例#23
0
    def test_custom_redirect_url(self, redirect, expected_url):
        """
        Test custom redirect after login
        """
        configuration_values = {"DEFAULT_REDIRECT_AFTER_LOGIN": redirect}
        req = self.request.get(settings.LOGIN_URL)
        req.META["HTTP_ACCEPT"] = "text/html"

        with with_site_configuration_context(
                configuration=configuration_values):
            next_page = get_next_url_for_login_page(req)

        self.assertEqual(next_page, expected_url)
示例#24
0
    def process_exception(self, request, exception):
        """Handles specific exception raised by Python Social Auth eg HTTPError."""

        referer_url = request.META.get('HTTP_REFERER', '')
        if (referer_url and isinstance(exception, HTTPError) and
                exception.response.status_code == 502):
            referer_url = urlparse.urlparse(referer_url).path
            if referer_url == reverse('signin_user'):
                messages.error(request, _('Unable to connect with the external provider, please try again'),
                               extra_tags='social-auth')

                redirect_url = get_next_url_for_login_page(request)
                return redirect('/login?next=' + redirect_url)

        return super(ExceptionMiddleware, self).process_exception(request, exception)
示例#25
0
    def process_exception(self, request, exception):
        """Handles specific exception raised by Python Social Auth eg HTTPError."""

        referer_url = request.META.get('HTTP_REFERER', '')
        if (referer_url and isinstance(exception, HTTPError) and
                exception.response.status_code == 502):
            referer_url = six.moves.urllib.parse.urlparse(referer_url).path
            if referer_url == reverse('signin_user'):
                messages.error(request, _('Unable to connect with the external provider, please try again'),
                               extra_tags='social-auth')

                redirect_url = get_next_url_for_login_page(request)
                return redirect('/login?next=' + redirect_url)

        return super(ExceptionMiddleware, self).process_exception(request, exception)
示例#26
0
    def render_auth_form(self, request, forus_params):
        """Render the combined login/registration form, defaulting to login

        This relies on the JS to asynchronously load the actual form from
        the user_api.
        """
        initial_mode = '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
        if request.user.is_authenticated():
            logout(request)
            delete_logged_in_cookies(request)
            return redirect(redirect_to)

        # Otherwise, render the combined login/registration page
        context = {
            'data': {
                'login_redirect_url':
                redirect_to,
                'initial_mode':
                initial_mode,
                'third_party_auth': {},
                'third_party_auth_hint':
                '',
                'platform_name':
                settings.PLATFORM_NAME,

                # 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.
                'registration_form_desc':
                self.get_registration_form_description(request, forus_params),
            },
            '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,
            'disable_footer': True,
        }

        return render_to_response('edraak_forus/auth.html', context)
示例#27
0
def register_user(request, extra_context=None):
    """
    Deprecated. To be replaced by :class:`user_authn.views.login_form.login_and_registration_form`.
    """
    # Determine the URL to redirect to following login:
    redirect_to = get_next_url_for_login_page(request)
    if request.user.is_authenticated:
        return redirect(redirect_to)

    external_auth_response = external_auth_register(request)
    if external_auth_response is not None:
        return external_auth_response

    context = {
        'login_redirect_url': redirect_to,  # This gets added to the query string of the "Sign In" button in the header
        'email': '',
        'name': '',
        'running_pipeline': None,
        'pipeline_urls': auth_pipeline_urls(pipeline.AUTH_ENTRY_REGISTER, redirect_url=redirect_to),
        'platform_name': configuration_helpers.get_value(
            'platform_name',
            settings.PLATFORM_NAME
        ),
        'selected_provider': '',
        'username': '',
    }

    if extra_context is not None:
        context.update(extra_context)

    if context.get("extauth_domain", '').startswith(settings.SHIBBOLETH_DOMAIN_PREFIX):
        return render_to_response('register-shib.html', context)

    # If third-party auth is enabled, prepopulate the form with data from the
    # selected provider.
    if third_party_auth.is_enabled() and pipeline.running(request):
        running_pipeline = pipeline.get(request)
        current_provider = provider.Registry.get_from_pipeline(running_pipeline)
        if current_provider is not None:
            overrides = current_provider.get_register_form_data(running_pipeline.get('kwargs'))
            overrides['running_pipeline'] = running_pipeline
            overrides['selected_provider'] = current_provider.name
            context.update(overrides)

    return render_to_response('register.html', context)
示例#28
0
 def get(self, request, **kwargs):
     context = {}
     if request.user.is_authenticated:
         return redirect(reverse('dashboard'))
     hc_specialization_list = hcspecializations.objects.all()
     specializations_list = specializations.objects.all()
     context["hc_specialization_list"] = hc_specialization_list
     context["specializations_list"] = specializations_list
     context["states"] = states.objects.all()
     redirect_to = get_next_url_for_login_page(request)
     if third_party_auth.is_enabled():
         providers = third_party_auth_context(request, redirect_to, '')
         #providers = {}
     else:
         providers = {}
     context["providers"] = providers
     context["redirect_to"] = redirect_to
     context["root_url"] = settings.LMS_ROOT_URL
     return render_to_response('login_email_phone.html',context)
    def test_http_exception_redirection(self):
        """
        Test ExceptionMiddleware is correctly redirected to login page
        when PSA raises HttpError exception.
        """

        request = RequestFactory().get("dummy_url")
        next_url = get_next_url_for_login_page(request)
        login_url = '/login?next=' + next_url
        request.META['HTTP_REFERER'] = 'http://example.com:8000/login'
        exception = HTTPError()
        exception.response = HttpResponse(status=502)

        # Add error message for error in auth pipeline
        MessageMiddleware().process_request(request)
        response = ExceptionMiddleware().process_exception(request, exception)
        target_url = response.url

        self.assertEqual(response.status_code, 302)
        self.assertTrue(target_url.endswith(login_url))
示例#30
0
    def render_auth_form(self, request, forus_params):
        """Render the combined login/registration form, defaulting to login

        This relies on the JS to asynchronously load the actual form from
        the user_api.
        """
        initial_mode = '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
        if request.user.is_authenticated():
            logout(request)
            delete_logged_in_cookies(request)
            return redirect(redirect_to)

        # Otherwise, render the combined login/registration page
        context = {
            'data': {
                'login_redirect_url': redirect_to,
                'initial_mode': initial_mode,
                'third_party_auth': {},
                'third_party_auth_hint': '',
                'platform_name': settings.PLATFORM_NAME,

                # 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.
                'registration_form_desc': self.get_registration_form_description(request, forus_params),
            },
            '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,
            'disable_footer': True,
        }

        return render_to_response('edraak_forus/auth.html', context)
示例#31
0
def ssl_login(request):
    """
    This is called by branding.views.index when
    FEATURES['AUTH_USE_CERTIFICATES'] = True

    Used for MIT user authentication.  This presumes the web server
    (nginx) has been configured to require specific client
    certificates.

    If the incoming protocol is HTTPS (SSL) then authenticate via
    client certificate.  The certificate provides user email and
    fullname; this populates the ExternalAuthMap.  The user is
    nevertheless still asked to complete the edX signup.

    Else continues on with student.views.index, and no authentication.
    """
    # Just to make sure we're calling this only at MIT:
    if not settings.FEATURES['AUTH_USE_CERTIFICATES']:
        return HttpResponseForbidden()

    cert = ssl_get_cert_from_request(request)

    if not cert:
        # no certificate information - go onward to main index
        return student.views.index(request)

    (_user, email, fullname) = _ssl_dn_extract_info(cert)

    redirect_to = get_next_url_for_login_page(request)
    retfun = functools.partial(redirect, redirect_to)
    return _external_login_or_signup(
        request,
        external_id=email,
        external_domain="ssl:MIT",
        credentials=cert,
        email=email,
        fullname=fullname,
        retfun=retfun
    )
示例#32
0
def ssl_login(request):
    """
    This is called by branding.views.index when
    FEATURES['AUTH_USE_CERTIFICATES'] = True

    Used for MIT user authentication.  This presumes the web server
    (nginx) has been configured to require specific client
    certificates.

    If the incoming protocol is HTTPS (SSL) then authenticate via
    client certificate.  The certificate provides user email and
    fullname; this populates the ExternalAuthMap.  The user is
    nevertheless still asked to complete the edX signup.

    Else continues on with student.views.index, and no authentication.
    """
    # Just to make sure we're calling this only at MIT:
    if not settings.FEATURES['AUTH_USE_CERTIFICATES']:
        return HttpResponseForbidden()

    cert = ssl_get_cert_from_request(request)

    if not cert:
        # no certificate information - go onward to main index
        return student.views.index(request)

    (_user, email, fullname) = _ssl_dn_extract_info(cert)

    redirect_to = get_next_url_for_login_page(request)
    retfun = functools.partial(redirect, redirect_to)
    return _external_login_or_signup(
        request,
        external_id=email,
        external_domain="ssl:MIT",
        credentials=cert,
        email=email,
        fullname=fullname,
        retfun=retfun
    )
示例#33
0
    def test_http_exception_redirection(self):
        """
        Test ExceptionMiddleware is correctly redirected to login page
        when PSA raises HttpError exception.
        """

        request = RequestFactory().get("dummy_url")
        next_url = get_next_url_for_login_page(request)
        login_url = '/login?next=' + next_url
        request.META['HTTP_REFERER'] = 'http://example.com:8000/login'
        exception = HTTPError()
        exception.response = HttpResponse(status=502)

        # Add error message for error in auth pipeline
        MessageMiddleware().process_request(request)
        response = ExceptionMiddleware().process_exception(
            request, exception
        )
        target_url = response.url

        self.assertEqual(response.status_code, 302)
        self.assertTrue(target_url.endswith(login_url))
示例#34
0
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
    if request.user.is_authenticated():
        return redirect(redirect_to)

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

    # If this is a themed site, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    # Themed sites can use the new logistration page by setting
    # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their
    # configuration settings.
    if is_request_in_themed_site() and not configuration_helpers.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # 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:
        try:
            next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query)
            provider_id = next_args['tpa_hint'][0]
            if third_party_auth.provider.Registry.get(provider_id=provider_id):
                third_party_auth_hint = provider_id
                initial_mode = "hinted_login"
        except (KeyError, ValueError, IndexError):
            pass

    # 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 or '',
            'platform_name': configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME),

            # 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']),
        },
        '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,
        'disable_footer': not configuration_helpers.get_value(
            'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER',
            settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER']
        ),
    }

    return render_to_response('student_account/login_and_register.html', context)
示例#35
0
def cme_create_account(request, post_override=None):
    '''
    JSON call to create new edX account; modified for the CME registration form.
    Used by form in signup_modal.html, which is included into navigation.html
    '''
    json_string = {'success': False}

    post_vars = post_override if post_override else request.POST.copy()

    # Confirm we have a properly formed request
    for var in ['username', 'email', 'password', 'name']:
        if var not in post_vars:
            json_string['value'] = "Error (401 {field}). E-mail us.".format(field=var)
            json_string['field'] = var
            return HttpResponse(json.dumps(json_string))

    # Validate required fields set1
    error = validate_required_fields_set1(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    # Validate length of middle initial
    error = validate_middle_initial_length(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    # Validate birth date
    error = validate_birth_date_format(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    # Validate fields dependent on Professional Designation
    error = validate_professional_fields(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    # Setup post_vars for correct sub_affiliation field
    post_vars = setup_sub_affiliation_field(post_vars)

    # Validate affiliation fields
    error = validate_affiliation_fields(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    # Validate required fields set2
    error = validate_required_fields_set2(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    # Validate required check boxes
    error = validate_required_boxes(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    # Validate required radio buttons
    # Commented out while no radios exist
#     error = validate_required_radios(post_vars)
#     if error is not None:
#         return HttpResponse(json.dumps(error))

    # Validate required secondary fields
    error = validate_required_secondaries(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    # Validate email address
    try:
        validate_email(post_vars['email'])
    except ValidationError:
        json_string['value'] = "Valid e-mail is required."
        json_string['field'] = 'email'
        return HttpResponse(json.dumps(json_string))

    # Validate username conforms
    try:
        validate_slug(post_vars['username'])
    except ValidationError:
        json_string['value'] = "Username should only consist of A-Z and 0-9, with no spaces."
        json_string['field'] = 'username'
        return HttpResponse(json.dumps(json_string))

    # Validate Export controls
    error = validate_export_controls(post_vars)
    if error is not None:
        return HttpResponse(json.dumps(error))

    # Ok, looks like everything is legit.  Create the account.
    ret = _do_cme_create_account(post_vars)
    if isinstance(ret, HttpResponse):  # if there was an error then return that
        return ret
    (user, cme_user_profile, registration) = ret

    email_dict = {
        'name': post_vars['name'],
        'key': registration.activation_key,
    }

    # composes activation email
    subject = render_to_string('emails/activation_email_subject.txt', email_dict)
    # Email subject *must not* contain newlines
    subject = ''.join(subject.splitlines())
    message = render_to_string('emails/activation_email.txt', email_dict)

    try:
        if settings.FEATURES.get('REROUTE_ACTIVATION_EMAIL'):
            dest_addr = settings.FEATURES['REROUTE_ACTIVATION_EMAIL']
            message = ("Activation for %s (%s): %s\n" % (user, user.email, cme_user_profile.name) +
                       '-' * 80 + '\n\n' + message)
            send_mail(subject, message, settings.DEFAULT_FROM_EMAIL, [dest_addr], fail_silently=False)
        else:
            user.email_user(subject, message, settings.DEFAULT_FROM_EMAIL)
    except:
        log.warning('Unable to send activation email to user', exc_info=True)
        json_string['value'] = 'Could not send activation e-mail.'
        return HttpResponse(json.dumps(json_string))

    # Immediately after a user creates an account, we log them in. They are only
    # logged in until they close the browser. They can't log in again until they click
    # the activation link from the email.
    login_user = authenticate(username=post_vars['username'], password=post_vars['password'])
    login(request, login_user)
    request.session.set_expiry(0)

    redirect_url = get_next_url_for_login_page(request)
    dog_stats_api.increment("common.student.successful_login")

    json_string = {'success': True,
                   'redirect_url': redirect_url}

    response = HttpResponse(json.dumps(json_string))

    return response
 def test_safe_next(self):
     """ Test safe next parameter """
     req = self.request.get(reverse("login") + "?next={url}".format(url="/dashboard"))
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, u'/dashboard')
示例#37
0
 def validate_login():
     req = self.request.get(reverse("login") + "?next={url}".format(url=next_url))
     req.META["HTTP_ACCEPT"] = "text/html"  # pylint: disable=no-member
     self._add_session(req)
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, expected_url)
示例#38
0
 def test_safe_next(self):
     """ Test safe next parameter """
     req = self.request.get(
         reverse("login") + "?next={url}".format(url="/dashboard"))
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, u'/dashboard')
示例#39
0
 def test_safe_next(self):
     """ Test safe next parameter """
     req = self.request.get(reverse("login") + "?next={url}".format(url="/dashboard"))
     req.META["HTTP_ACCEPT"] = "text/html"  # pylint: disable=no-member
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, u'/dashboard')
示例#40
0
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
    if request.user.is_authenticated():
        return redirect(redirect_to)

    # 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:
        try:
            next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query)
            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.
                    return redirect(
                        pipeline.get_login_url(provider_id,
                                               pipeline.AUTH_ENTRY_LOGIN,
                                               redirect_url=redirect_to))
                third_party_auth_hint = provider_id
                initial_mode = "hinted_login"
        except (KeyError, ValueError, IndexError):
            pass

    # If this is a themed site, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    # Themed sites can use the new logistration page by setting
    # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their
    # configuration settings.
    if is_request_in_themed_site() and not configuration_helpers.get_value(
            'ENABLE_COMBINED_LOGIN_REGISTRATION', False):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # 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]

    # 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,

            # 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))
        },
        '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']),
    }

    context = update_context_for_enterprise(request, context)

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

    # Remove enterprise cookie so that subsequent requests show default login page.
    response.delete_cookie(
        configuration_helpers.get_value(
            "ENTERPRISE_CUSTOMER_COOKIE_NAME",
            settings.ENTERPRISE_CUSTOMER_COOKIE_NAME),
        domain=configuration_helpers.get_value("BASE_COOKIE_DOMAIN",
                                               settings.BASE_COOKIE_DOMAIN),
    )

    return response
示例#41
0
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
    if request.user.is_authenticated:
        return redirect(redirect_to)

    # 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:
        try:
            next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query)
            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.error("Unknown tpa_hint provider: %s", ex)

    # If this is a themed site, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    # Themed sites can use the new logistration page by setting
    # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their
    # configuration settings.
    if is_request_in_themed_site() and not configuration_helpers.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # 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
    ]

    # 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,

            # 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))
        },
        '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']
        ),
    }

    enterprise_customer = enterprise_customer_for_request(request)
    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
示例#42
0
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
    if request.user.is_authenticated():
        return redirect(redirect_to)

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

    # If this is a themed site, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    # Themed sites can use the new logistration page by setting
    # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their theme/microsite
    # configuration settings.
    if is_request_in_themed_site() and not get_themed_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # 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:
        try:
            next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query)
            provider_id = next_args['tpa_hint'][0]
            if third_party_auth.provider.Registry.get(provider_id=provider_id):
                third_party_auth_hint = provider_id
                initial_mode = "hinted_login"
        except (KeyError, ValueError, IndexError):
            pass

    # 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 or '',
            'platform_name': get_themed_value('PLATFORM_NAME', settings.PLATFORM_NAME),

            # 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']),
        },
        '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,
        'disable_footer': True,
    }

    return render_to_response('student_account/login_and_register.html', context)
示例#43
0
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: We check for the existence of login-related cookies in addition to is_authenticated
    #  since Django's SessionAuthentication middleware auto-updates session cookies but not
    #  the other login-related cookies. See ARCH-282.
    if request.user.is_authenticated and are_logged_in_cookies_set(request):
        return redirect(redirect_to)

    # 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:
        try:
            next_args = six.moves.urllib.parse.parse_qs(six.moves.urllib.parse.urlparse(redirect_to).query)
            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(u"Unknown tpa_hint provider: %s", ex)

    # We are defaulting to true because all themes should now be using the newer page.
    if is_request_in_themed_site() and not configuration_helpers.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', True):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # 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()
        },
        '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']
        ),
    }

    enterprise_customer = enterprise_customer_for_request(request)
    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
示例#44
0
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
    if UserProfile.has_registered(request.user):
        return redirect(redirect_to)

    if third_party_auth.is_enabled():
        force_provider_id = settings.FORCED_TPA_PROVIDER_ID
        if force_provider_id:
            force_provider = third_party_auth.provider.Registry.get(
                provider_id=force_provider_id,
            )
            if force_provider and force_provider.display_for_login:
                running_pipeline = third_party_auth.pipeline.get(request)
                if not running_pipeline:
                    if initial_mode in [pipeline.AUTH_ENTRY_LOGIN, pipeline.AUTH_ENTRY_REGISTER]:
                        tpa_url = pipeline.get_login_url(
                            force_provider_id,
                            initial_mode,
                            redirect_url=redirect_to,
                        )
                        return redirect(tpa_url)

    # 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:
        try:
            next_args = urlparse.parse_qs(urlparse.urlparse(redirect_to).query)
            provider_id = next_args['tpa_hint'][0]
            if third_party_auth.provider.Registry.get(provider_id=provider_id):
                third_party_auth_hint = provider_id
                initial_mode = "hinted_login"
        except (KeyError, ValueError, IndexError):
            pass

    set_enterprise_branding_filter_param(request=request, provider_id=third_party_auth_hint)

    # If this is a themed site, revert to the old login/registration pages.
    # We need to do this for now to support existing themes.
    # Themed sites can use the new logistration page by setting
    # 'ENABLE_COMBINED_LOGIN_REGISTRATION' in their
    # configuration settings.
    if is_request_in_themed_site() and not configuration_helpers.get_value('ENABLE_COMBINED_LOGIN_REGISTRATION', False):
        if initial_mode == "login":
            return old_login_view(request)
        elif initial_mode == "register":
            return old_register_view(request)

    # Allow external auth to intercept and handle the request
    ext_auth_response = _external_auth_intercept(request, initial_mode)
    if ext_auth_response is not None:
        return ext_auth_response

    # 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 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),
            'privacy_policy_url': marketing_link('PRIVACY'),

            # 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']),
        },
        '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,
        'disable_footer': not configuration_helpers.get_value(
            'ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER',
            settings.FEATURES['ENABLE_COMBINED_LOGIN_REGISTRATION_FOOTER']
        ),
    }

    return render_to_response('student_account/login_and_register.html', context)
示例#45
0
 def test_safe_next(self, url, host, expected_url):
     """ Test safe next parameter """
     req = self.request.get(reverse("login") + "?next={url}".format(url=url), HTTP_HOST=host)
     req.META["HTTP_ACCEPT"] = "text/html"  # pylint: disable=no-member
     next_page = get_next_url_for_login_page(req)
     self.assertEqual(next_page, expected_url)
示例#46
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'])
        elif settings.FEATURES.get('ENABLE_LOGIN_MICROFRONTEND'):
            redirect_url = get_next_url_for_login_page(request)

        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