Пример #1
0
    def base_extauth_bypass_sending_activation_email(self,
                                                     bypass_activation_email):
        """
        Tests user creation without sending activation email when
        doing external auth
        """

        request = self.request_factory.post(self.url, self.params)
        request.site = self.site
        # now indicate we are doing ext_auth by setting 'ExternalAuthMap' in the session.
        request.session = import_module(
            settings.SESSION_ENGINE).SessionStore()  # empty session
        extauth = ExternalAuthMap(
            external_id='*****@*****.**',
            external_email='*****@*****.**',
            internal_password=self.params['password'],
            external_domain='shib:https://idp.stanford.edu/')
        request.session['ExternalAuthMap'] = extauth
        request.user = AnonymousUser()

        with mock.patch('edxmako.request_context.get_current_request',
                        return_value=request):
            with mock.patch('django.core.mail.send_mail') as mock_send_mail:
                create_account(request)

        # check that send_mail is called
        if bypass_activation_email:
            self.assertFalse(mock_send_mail.called)
        else:
            self.assertTrue(mock_send_mail.called)
Пример #2
0
    def test_new_account_registration_fails_if_email_exists(self):
        request, strategy = self.get_request_and_strategy(
            auth_entry=pipeline.AUTH_ENTRY_REGISTER, redirect_uri='social:complete')
        backend = strategy.request.backend
        backend.auth_complete = mock.MagicMock(return_value=self.fake_auth_complete(strategy))
        # pylint: disable=protected-access
        self.assert_redirect_to_register_looks_correct(actions.do_complete(backend, social_views._do_login,
                                                                           request=request))

        with self._patch_edxmako_current_request(request):
            self.assert_register_response_in_pipeline_looks_correct(
                register_user(strategy.request),
                pipeline.get(request)['kwargs'],
                ['name', 'username', 'email']
            )

        with self._patch_edxmako_current_request(strategy.request):
            strategy.request.POST = self.get_registration_post_vars()
            # Create twice: once successfully, and once causing a collision.
            create_account(strategy.request)
        self.assert_json_failure_response_is_username_collision(create_account(strategy.request))
Пример #3
0
    def test_new_account_registration_fails_if_email_exists(self):
        request, strategy = self.get_request_and_strategy(
            auth_entry=pipeline.AUTH_ENTRY_REGISTER, redirect_uri='social:complete')
        backend = strategy.request.backend
        backend.auth_complete = mock.MagicMock(return_value=self.fake_auth_complete(strategy))
        # pylint: disable=protected-access
        self.assert_redirect_to_register_looks_correct(actions.do_complete(backend, social_views._do_login,
                                                                           request=request))

        with self._patch_edxmako_current_request(request):
            self.assert_register_response_in_pipeline_looks_correct(
                register_user(strategy.request),
                pipeline.get(request)['kwargs'],
                ['name', 'username', 'email']
            )

        with self._patch_edxmako_current_request(strategy.request):
            strategy.request.POST = self.get_registration_post_vars()
            # Create twice: once successfully, and once causing a collision.
            create_account(strategy.request)
        self.assert_json_failure_response_is_username_collision(create_account(strategy.request))
Пример #4
0
    def test_ext_auth_password_length_too_short(self):
        """
        Tests that even if password policy is enforced, ext_auth registrations aren't subject to it
        """
        self.url_params['password'] = u'aaa'  # shouldn't pass validation
        request = self.request_factory.post(self.url, self.url_params)
        request.site = SiteFactory.create()
        # now indicate we are doing ext_auth by setting 'ExternalAuthMap' in the session.
        request.session = import_module(settings.SESSION_ENGINE).SessionStore()  # empty session
        extauth = ExternalAuthMap(external_id='*****@*****.**',
                                  external_email='*****@*****.**',
                                  internal_password=self.url_params['password'],
                                  external_domain='shib:https://idp.stanford.edu/')
        request.session['ExternalAuthMap'] = extauth
        request.user = AnonymousUser()

        with patch('edxmako.request_context.get_current_request', return_value=request):
            response = create_account(request)
        self.assertEqual(response.status_code, 200)
        obj = json.loads(response.content)
        self.assertTrue(obj['success'])
    def test_ext_auth_password_length_too_short(self):
        """
        Tests that even if password policy is enforced, ext_auth registrations aren't subject to it
        """
        self.url_params['password'] = '******'  # shouldn't pass validation
        request = self.request_factory.post(self.url, self.url_params)
        request.site = SiteFactory.create()
        # now indicate we are doing ext_auth by setting 'ExternalAuthMap' in the session.
        request.session = import_module(settings.SESSION_ENGINE).SessionStore()  # empty session
        extauth = ExternalAuthMap(external_id='*****@*****.**',
                                  external_email='*****@*****.**',
                                  internal_password=self.url_params['password'],
                                  external_domain='shib:https://idp.stanford.edu/')
        request.session['ExternalAuthMap'] = extauth
        request.user = AnonymousUser()

        with patch('edxmako.request_context.get_current_request', return_value=request):
            response = create_account(request)
        self.assertEqual(response.status_code, 200)
        obj = json.loads(response.content)
        self.assertTrue(obj['success'])
Пример #6
0
    def test_full_pipeline_succeeds_registering_new_account(self):
        # First, create, the request and strategy that store pipeline state.
        # Mock out wire traffic.
        request, strategy = self.get_request_and_strategy(
            auth_entry=pipeline.AUTH_ENTRY_REGISTER, redirect_uri='social:complete')
        strategy.request.backend.auth_complete = mock.MagicMock(return_value=self.fake_auth_complete(strategy))

        # Begin! Grab the registration page and check the login control on it.
        self.assert_register_response_before_pipeline_looks_correct(self.client.get('/register'))

        # The pipeline starts by a user GETting /auth/login/<provider>.
        # Synthesize that request and check that it redirects to the correct
        # provider page.
        self.assert_redirect_to_provider_looks_correct(self.client.get(
            pipeline.get_login_url(self.provider.provider_id, pipeline.AUTH_ENTRY_LOGIN)))

        # Next, the provider makes a request against /auth/complete/<provider>.
        # pylint: disable=protected-access
        self.assert_redirect_to_register_looks_correct(actions.do_complete(request.backend, social_views._do_login,
                                                                           request=request))

        # At this point we know the pipeline has resumed correctly. Next we
        # fire off the view that displays the registration form.
        with self._patch_edxmako_current_request(request):
            self.assert_register_response_in_pipeline_looks_correct(
                register_user(strategy.request),
                pipeline.get(request)['kwargs'],
                ['name', 'username', 'email']
            )

        # Next, we invoke the view that handles the POST. Not all providers
        # supply email. Manually add it as the user would have to; this
        # also serves as a test of overriding provider values. Always provide a
        # password for us to check that we override it properly.
        overridden_password = strategy.request.POST.get('password')
        email = '*****@*****.**'

        if not strategy.request.POST.get('email'):
            strategy.request.POST = self.get_registration_post_vars({'email': email})

        # The user must not exist yet...
        with self.assertRaises(auth_models.User.DoesNotExist):
            self.get_user_by_email(strategy, email)

        # ...but when we invoke create_account the existing edX view will make
        # it, but not social auths. The pipeline creates those later.
        with self._patch_edxmako_current_request(strategy.request):
            self.assert_json_success_response_looks_correct(create_account(strategy.request))
        # We've overridden the user's password, so authenticate() with the old
        # value won't work:
        created_user = self.get_user_by_email(strategy, email)
        self.assert_password_overridden_by_pipeline(overridden_password, created_user.username)

        # At this point the user object exists, but there is no associated
        # social auth.
        self.assert_social_auth_does_not_exist_for_user(created_user, strategy)

        # We should be redirected back to the complete page, setting
        # the "logged in" cookie for the marketing site.
        self.assert_logged_in_cookie_redirect(actions.do_complete(
            request.backend, social_views._do_login, request.user, None,  # pylint: disable=protected-access
            redirect_field_name=auth.REDIRECT_FIELD_NAME, request=request
        ))

        # Set the cookie and try again
        self.set_logged_in_cookies(request)
        self.assert_redirect_to_dashboard_looks_correct(
            actions.do_complete(strategy.request.backend, social_views._do_login, user=created_user, request=request))
        # Now the user has been redirected to the dashboard. Their third party account should now be linked.
        self.assert_social_auth_exists_for_user(created_user, strategy)
        self.assert_account_settings_context_looks_correct(account_settings_context(request), linked=True)
Пример #7
0
    def test_full_pipeline_succeeds_registering_new_account(self):
        # First, create, the request and strategy that store pipeline state.
        # Mock out wire traffic.
        request, strategy = self.get_request_and_strategy(
            auth_entry=pipeline.AUTH_ENTRY_REGISTER, redirect_uri='social:complete')
        strategy.request.backend.auth_complete = mock.MagicMock(return_value=self.fake_auth_complete(strategy))

        # Begin! Grab the registration page and check the login control on it.
        self.assert_register_response_before_pipeline_looks_correct(self.client.get('/register'))

        # The pipeline starts by a user GETting /auth/login/<provider>.
        # Synthesize that request and check that it redirects to the correct
        # provider page.
        self.assert_redirect_to_provider_looks_correct(self.client.get(
            pipeline.get_login_url(self.provider.provider_id, pipeline.AUTH_ENTRY_LOGIN)))

        # Next, the provider makes a request against /auth/complete/<provider>.
        # pylint: disable=protected-access
        self.assert_redirect_to_register_looks_correct(actions.do_complete(request.backend, social_views._do_login,
                                                                           request=request))

        # At this point we know the pipeline has resumed correctly. Next we
        # fire off the view that displays the registration form.
        with self._patch_edxmako_current_request(request):
            self.assert_register_response_in_pipeline_looks_correct(
                register_user(strategy.request),
                pipeline.get(request)['kwargs'],
                ['name', 'username', 'email']
            )

        # Next, we invoke the view that handles the POST. Not all providers
        # supply email. Manually add it as the user would have to; this
        # also serves as a test of overriding provider values. Always provide a
        # password for us to check that we override it properly.
        overridden_password = strategy.request.POST.get('password')
        email = '*****@*****.**'

        if not strategy.request.POST.get('email'):
            strategy.request.POST = self.get_registration_post_vars({'email': email})

        # The user must not exist yet...
        with self.assertRaises(auth_models.User.DoesNotExist):
            self.get_user_by_email(strategy, email)

        # ...but when we invoke create_account the existing edX view will make
        # it, but not social auths. The pipeline creates those later.
        with self._patch_edxmako_current_request(strategy.request):
            self.assert_json_success_response_looks_correct(create_account(strategy.request))
        # We've overridden the user's password, so authenticate() with the old
        # value won't work:
        created_user = self.get_user_by_email(strategy, email)
        self.assert_password_overridden_by_pipeline(overridden_password, created_user.username)

        # At this point the user object exists, but there is no associated
        # social auth.
        self.assert_social_auth_does_not_exist_for_user(created_user, strategy)

        # We should be redirected back to the complete page, setting
        # the "logged in" cookie for the marketing site.
        self.assert_logged_in_cookie_redirect(actions.do_complete(
            request.backend, social_views._do_login, request.user, None,  # pylint: disable=protected-access
            redirect_field_name=auth.REDIRECT_FIELD_NAME, request=request
        ))

        # Set the cookie and try again
        self.set_logged_in_cookies(request)
        self.assert_redirect_after_pipeline_completes(
            actions.do_complete(strategy.request.backend, social_views._do_login, user=created_user, request=request))
        # Now the user has been redirected to the dashboard. Their third party account should now be linked.
        self.assert_social_auth_exists_for_user(created_user, strategy)
        self.assert_account_settings_context_looks_correct(account_settings_context(request), linked=True)
Пример #8
0
def _signup(request, eamap, retfun=None):
    """
    Present form to complete for signup via external authentication.
    Even though the user has external credentials, he/she still needs
    to create an account on the edX system, and fill in the user
    registration form.

    eamap is an ExternalAuthMap object, specifying the external user
    for which to complete the signup.

    retfun is a function to execute for the return value, if immediate
    signup is used.  That allows @ssl_login_shortcut() to work.
    """
    from openedx.core.djangoapps.user_authn.views.deprecated import create_account, register_user

    # save this for use by create_account
    request.session['ExternalAuthMap'] = eamap

    if settings.FEATURES.get('AUTH_USE_CERTIFICATES_IMMEDIATE_SIGNUP', ''):
        # do signin immediately, by calling create_account, instead of asking
        # student to fill in form.  MIT students already have information filed.
        username = eamap.external_email.split('@', 1)[0]
        username = username.replace('.', '_')
        post_vars = dict(username=username,
                         honor_code=u'true',
                         terms_of_service=u'true')
        log.info(u'doing immediate signup for %s, params=%s', username,
                 post_vars)
        create_account(request, post_vars)
        # should check return content for successful completion before
        if retfun is not None:
            return retfun()
        else:
            return redirect('/')

    # default conjoin name, no spaces, flattened to ascii b/c django can't handle unicode usernames, sadly
    # but this only affects username, not fullname
    username = re.sub(r'\s',
                      '',
                      _flatten_to_ascii(eamap.external_name),
                      flags=re.UNICODE)

    context = {
        'has_extauth_info': True,
        'show_signup_immediately': True,
        'extauth_domain': eamap.external_domain,
        'extauth_id': eamap.external_id,
        'extauth_email': eamap.external_email,
        'extauth_username': username,
        'extauth_name': eamap.external_name,
        'ask_for_tos': True,
    }

    # Some openEdX instances can't have terms of service for shib users, like
    # according to Stanford's Office of General Counsel
    uses_shibboleth = (
        settings.FEATURES.get('AUTH_USE_SHIB')
        and eamap.external_domain.startswith(SHIBBOLETH_DOMAIN_PREFIX))
    if uses_shibboleth and settings.FEATURES.get('SHIB_DISABLE_TOS'):
        context['ask_for_tos'] = False

    # detect if full name is blank and ask for it from user
    context['ask_for_fullname'] = eamap.external_name.strip() == ''

    # validate provided mail and if it's not valid ask the user
    try:
        validate_email(eamap.external_email)
        context['ask_for_email'] = False
    except ValidationError:
        context['ask_for_email'] = True

    log.info(u'EXTAUTH: Doing signup for %s', eamap.external_id)

    return register_user(request, extra_context=context)
Пример #9
0
def _signup(request, eamap, retfun=None):
    """
    Present form to complete for signup via external authentication.
    Even though the user has external credentials, he/she still needs
    to create an account on the edX system, and fill in the user
    registration form.

    eamap is an ExternalAuthMap object, specifying the external user
    for which to complete the signup.

    retfun is a function to execute for the return value, if immediate
    signup is used.  That allows @ssl_login_shortcut() to work.
    """
    from openedx.core.djangoapps.user_authn.views.deprecated import create_account, register_user

    # save this for use by create_account
    request.session['ExternalAuthMap'] = eamap

    if settings.FEATURES.get('AUTH_USE_CERTIFICATES_IMMEDIATE_SIGNUP', ''):
        # do signin immediately, by calling create_account, instead of asking
        # student to fill in form.  MIT students already have information filed.
        username = eamap.external_email.split('@', 1)[0]
        username = username.replace('.', '_')
        post_vars = dict(username=username,
                         honor_code=u'true',
                         terms_of_service=u'true')
        log.info(u'doing immediate signup for %s, params=%s', username, post_vars)
        create_account(request, post_vars)
        # should check return content for successful completion before
        if retfun is not None:
            return retfun()
        else:
            return redirect('/')

    # default conjoin name, no spaces, flattened to ascii b/c django can't handle unicode usernames, sadly
    # but this only affects username, not fullname
    username = re.sub(r'\s', '', _flatten_to_ascii(eamap.external_name), flags=re.UNICODE)

    context = {
        'has_extauth_info': True,
        'show_signup_immediately': True,
        'extauth_domain': eamap.external_domain,
        'extauth_id': eamap.external_id,
        'extauth_email': eamap.external_email,
        'extauth_username': username,
        'extauth_name': eamap.external_name,
        'ask_for_tos': True,
    }

    # Some openEdX instances can't have terms of service for shib users, like
    # according to Stanford's Office of General Counsel
    uses_shibboleth = (settings.FEATURES.get('AUTH_USE_SHIB') and
                       eamap.external_domain.startswith(SHIBBOLETH_DOMAIN_PREFIX))
    if uses_shibboleth and settings.FEATURES.get('SHIB_DISABLE_TOS'):
        context['ask_for_tos'] = False

    # detect if full name is blank and ask for it from user
    context['ask_for_fullname'] = eamap.external_name.strip() == ''

    # validate provided mail and if it's not valid ask the user
    try:
        validate_email(eamap.external_email)
        context['ask_for_email'] = False
    except ValidationError:
        context['ask_for_email'] = True

    log.info(u'EXTAUTH: Doing signup for %s', eamap.external_id)

    return register_user(request, extra_context=context)