Ejemplo n.º 1
0
    def test_externalauth_login_required_course_context(self):
        """
        Tests the redirects when visiting course-specific URL with @login_required.
        Should vary by course depending on its enrollment_domain
        """
        target_url = reverse('courseware', args=[text_type(self.course.id)])
        noshib_response = self.client.get(target_url, follow=True, HTTP_ACCEPT="text/html")
        self.assertEqual(noshib_response.redirect_chain[-1],
                         (expected_redirect_url('/login?next={url}'.format(url=target_url)), 302))
        self.assertContains(noshib_response, (u"Sign in or Register | {platform_name}"
                                              .format(platform_name=settings.PLATFORM_NAME)))
        self.assertEqual(noshib_response.status_code, 200)

        target_url_shib = reverse('courseware', args=[text_type(self.shib_course.id)])
        shib_response = self.client.get(**{'path': target_url_shib,
                                           'follow': True,
                                           'REMOTE_USER': self.extauth.external_id,
                                           'Shib-Identity-Provider': 'https://idp.stanford.edu/',
                                           'HTTP_ACCEPT': "text/html"})
        # Test that the shib-login redirect page with ?next= and the desired page are part of the redirect chain
        # The 'courseware' page actually causes a redirect itself, so it's not the end of the chain and we
        # won't test its contents
        self.assertEqual(shib_response.redirect_chain[-3],
                         (expected_redirect_url('/shib-login/?next={url}'.format(url=target_url_shib)), 302))
        self.assertEqual(shib_response.redirect_chain[-2],
                         (expected_redirect_url(target_url_shib), 302))
        self.assertEqual(shib_response.status_code, 200)
Ejemplo n.º 2
0
    def test_wiki_redirect(self):
        """
        Test that requesting wiki URLs redirect properly to or out of classes.

        An enrolled in student going from /courses/edX/toy/2012_Fall/progress
        to /wiki/some/fake/wiki/page/ will redirect to
        /courses/edX/toy/2012_Fall/wiki/some/fake/wiki/page/

        An unenrolled student going to /courses/edX/toy/2012_Fall/wiki/some/fake/wiki/page/
        will be redirected to /wiki/some/fake/wiki/page/

        """
        self.login(self.student, self.password)

        self.enroll(self.toy)

        referer = reverse("progress", kwargs={'course_id': text_type(self.toy.id)})
        destination = reverse("wiki:get", kwargs={'path': 'some/fake/wiki/page/'})

        redirected_to = referer.replace("progress", "wiki/some/fake/wiki/page/")

        resp = self.client.get(destination, HTTP_REFERER=referer)
        self.assertEqual(resp.status_code, 302)

        self.assertEqual(resp['Location'], expected_redirect_url(redirected_to))

        # Now we test that the student will be redirected away from that page if the course doesn't exist
        # We do this in the same test because we want to make sure the redirected_to is constructed correctly
        # This is a location like /courses/*/wiki/* , but with an invalid course ID
        bad_course_wiki_page = redirected_to.replace(self.toy.location.course, "bad_course")

        resp = self.client.get(bad_course_wiki_page, HTTP_REFERER=referer)
        self.assertEqual(resp.status_code, 302)
        self.assertEqual(resp['Location'], expected_redirect_url(destination))
Ejemplo n.º 3
0
    def test_wiki_redirect(self):
        """
        Test that requesting wiki URLs redirect properly to or out of classes.

        An enrolled in student going from /courses/edX/toy/2012_Fall/progress
        to /wiki/some/fake/wiki/page/ will redirect to
        /courses/edX/toy/2012_Fall/wiki/some/fake/wiki/page/

        An unenrolled student going to /courses/edX/toy/2012_Fall/wiki/some/fake/wiki/page/
        will be redirected to /wiki/some/fake/wiki/page/

        """
        self.login(self.student, self.password)

        self.enroll(self.toy)

        referer = reverse("progress", kwargs={'course_id': self.toy.id.to_deprecated_string()})
        destination = reverse("wiki:get", kwargs={'path': 'some/fake/wiki/page/'})

        redirected_to = referer.replace("progress", "wiki/some/fake/wiki/page/")

        resp = self.client.get(destination, HTTP_REFERER=referer)
        self.assertEqual(resp.status_code, 302)

        self.assertEqual(resp['Location'], expected_redirect_url(redirected_to))

        # Now we test that the student will be redirected away from that page if the course doesn't exist
        # We do this in the same test because we want to make sure the redirected_to is constructed correctly
        # This is a location like /courses/*/wiki/* , but with an invalid course ID
        bad_course_wiki_page = redirected_to.replace(self.toy.location.course, "bad_course")

        resp = self.client.get(bad_course_wiki_page, HTTP_REFERER=referer)
        self.assertEqual(resp.status_code, 302)
        self.assertEqual(resp['Location'], expected_redirect_url(destination))
Ejemplo n.º 4
0
 def _test_return_login(self, user_is_activated=True, previous_session_timed_out=False):
     """ Test logging in to an account that is already linked. """
     # Make sure we're not logged in:
     dashboard_response = self.client.get(reverse('dashboard'))
     self.assertEqual(dashboard_response.status_code, 302)
     # The user goes to the login page, and sees a button to login with this provider:
     provider_login_url = self._check_login_page()
     # The user clicks on the provider's login button:
     try_login_response = self.client.get(provider_login_url)
     # The user should be redirected to the provider:
     self.assertEqual(try_login_response.status_code, 302)
     login_response = self.do_provider_login(try_login_response['Location'])
     # If the previous session was manually logged out, there will be one weird redirect
     # required to set the login cookie (it sticks around if the main session times out):
     if not previous_session_timed_out:
         self.assertEqual(login_response.status_code, 302)
         expected_url = expected_redirect_url(self.complete_url, hostname=self.hostname)
         # TODO: Remove Django 1.11 upgrade shim
         # SHIM: Get rid of this logic post-upgrade
         if django.VERSION >= (1, 9):
             expected_url = "{}?".format(expected_url)
         self.assertEqual(login_response['Location'], expected_url)
         # And then we should be redirected to the dashboard:
         login_response = self.client.get(login_response['Location'])
         self.assertEqual(login_response.status_code, 302)
     if user_is_activated:
         url_expected = reverse('dashboard')
     else:
         url_expected = reverse('third_party_inactive_redirect') + '?next=' + reverse('dashboard')
     self.assertEqual(login_response['Location'], expected_redirect_url(url_expected, hostname=self.hostname))
     # Now we are logged in:
     dashboard_response = self.client.get(reverse('dashboard'))
     self.assertEqual(dashboard_response.status_code, 200)
Ejemplo n.º 5
0
    def test_login(self):
        self.user = UserFactory.create()  # pylint: disable=attribute-defined-outside-init
        # The user goes to the login page, and sees a button to login with this provider:
        provider_login_url = self._check_login_page()
        # The user clicks on the provider's button:
        try_login_response = self.client.get(provider_login_url)
        # The user should be redirected to the provider's login page:
        self.assertEqual(try_login_response.status_code, 302)
        complete_response = self.do_provider_login(try_login_response['Location'])
        # We should be redirected to the login screen since this account is not linked to an edX account:
        self.assertEqual(complete_response.status_code, 302)
        self.assertEqual(complete_response['Location'], expected_redirect_url(self.login_page_url, hostname=self.hostname))
        login_response = self.client.get(self.login_page_url)
        tpa_context = login_response.context["data"]["third_party_auth"]
        self.assertEqual(tpa_context["errorMessage"], None)
        # Check that the "You've successfully signed into [PROVIDER_NAME]" message is shown.
        self.assertEqual(tpa_context["currentProvider"], self.PROVIDER_NAME)
        # Now the user enters their username and password.
        # The AJAX on the page will log them in:
        ajax_login_response = self.client.post(
            reverse('user_api_login_session'),
            {'email': self.user.email, 'password': '******'}
        )
        self.assertEqual(ajax_login_response.status_code, 200)
        # Then the AJAX will finish the third party auth:
        continue_response = self.client.get(tpa_context["finishAuthUrl"])
        # And we should be redirected to the dashboard:
        self.assertEqual(continue_response.status_code, 302)
        self.assertEqual(continue_response['Location'], expected_redirect_url(reverse('dashboard'), hostname=self.hostname))

        # Now check that we can login again:
        self.client.logout()
        self._test_return_login()
Ejemplo n.º 6
0
    def test_register(self, **extra_defaults):
        # The user goes to the register page, and sees a button to register with the provider:
        provider_register_url = self._check_register_page()
        # The user clicks on the Dummy button:
        try_login_response = self.client.get(provider_register_url)
        # The user should be redirected to the provider's login page:
        self.assertEqual(try_login_response.status_code, 302)
        provider_response = self.do_provider_login(try_login_response['Location'])
        # We should be redirected to the register screen since this account is not linked to an edX account:
        self.assertEqual(provider_response.status_code, 302)
        self.assertEqual(provider_response['Location'], expected_redirect_url(self.register_page_url, hostname=self.hostname))
        register_response = self.client.get(self.register_page_url)
        tpa_context = register_response.context["data"]["third_party_auth"]
        self.assertEqual(tpa_context["errorMessage"], None)
        # Check that the "You've successfully signed into [PROVIDER_NAME]" message is shown.
        self.assertEqual(tpa_context["currentProvider"], self.PROVIDER_NAME)
        # Check that the data (e.g. email) from the provider is displayed in the form:
        form_data = register_response.context['data']['registration_form_desc']
        form_fields = {field['name']: field for field in form_data['fields']}
        self.assertEqual(form_fields['email']['defaultValue'], self.USER_EMAIL)
        self.assertEqual(form_fields['name']['defaultValue'], self.USER_NAME)
        self.assertEqual(form_fields['username']['defaultValue'], self.USER_USERNAME)
        for field_name, value in extra_defaults.items():
            self.assertEqual(form_fields[field_name]['defaultValue'], value)
        registration_values = {
            'email': '*****@*****.**',
            'name': 'My Customized Name',
            'username': '******',
            'honor_code': True,
        }
        # Now complete the form:
        ajax_register_response = self.client.post(
            reverse('user_api_registration'),
            registration_values
        )
        self.assertEqual(ajax_register_response.status_code, 200)
        # Then the AJAX will finish the third party auth:
        continue_response = self.client.get(tpa_context["finishAuthUrl"])
        # And we should be redirected to the dashboard:
        self.assertEqual(continue_response.status_code, 302)
        self.assertEqual(continue_response['Location'], expected_redirect_url(reverse('dashboard'), hostname=self.hostname))

        # Now check that we can login again, whether or not we have yet verified the account:
        self.client.logout()
        self._test_return_login(user_is_activated=False)

        self.client.logout()
        self.verify_user_email('*****@*****.**')
        self._test_return_login(user_is_activated=True)
Ejemplo n.º 7
0
    def test_ssl_cms_redirection(self):
        """
        Auto signup auth user and ensure they return to the original
        url they visited after being logged in.
        """
        course = CourseFactory.create(
            org='MITx',
            number='999',
            display_name='Robot Super Course'
        )

        with self._create_ssl_request('/') as request:
            external_auth_views.ssl_login(request)
        user = User.objects.get(email=self.USER_EMAIL)
        CourseEnrollment.enroll(user, course.id)

        CourseStaffRole(course.id).add_users(user)
        course_private_url = reverse('course_handler', args=(unicode(course.id),))
        self.assertNotIn(SESSION_KEY, self.client.session)

        response = self.client.get(
            course_private_url,
            follow=True,
            SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL),
            HTTP_ACCEPT='text/html'
        )
        self.assertEqual((expected_redirect_url(course_private_url), 302),
                         response.redirect_chain[-1])
        self.assertIn(SESSION_KEY, self.client.session)
Ejemplo n.º 8
0
    def create_course_page(self, course):
        """
        Test that loading the course wiki page creates the wiki page.
        The user must be enrolled in the course to see the page.
        """

        course_wiki_home = reverse('course_wiki',
                                   kwargs={'course_id': text_type(course.id)})
        referer = reverse("progress",
                          kwargs={'course_id': text_type(course.id)})

        resp = self.client.get(course_wiki_home,
                               follow=True,
                               HTTP_REFERER=referer)

        course_wiki_page = referer.replace('progress',
                                           'wiki/' + course.wiki_slug + "/")

        ending_location = resp.redirect_chain[-1][0]

        self.assertEquals(ending_location,
                          expected_redirect_url(course_wiki_page))
        self.assertEquals(resp.status_code, 200)

        self.has_course_navigator(resp)
        self.assertContains(
            resp, '<h3 class="entry-title">{}</h3>'.format(
                course.display_name_with_default))
Ejemplo n.º 9
0
 def test_login_required_dashboard(self):
     """
     Tests redirects to when @login_required to dashboard, which should always be the normal login,
     since there is no course context
     """
     response = self.client.get(reverse('dashboard'))
     self.assertEqual(response.status_code, 302)
     self.assertEqual(response['Location'], expected_redirect_url('/login?next=/dashboard'))
Ejemplo n.º 10
0
 def test_settings_tpa_hinted_login_dialog_disabled(self, url_name, auth_entry):
     """Test that the dialog doesn't show up for hinted logins when disabled via settings.THIRD_PARTY_AUTH_HINT. """
     self.google_provider.skip_hinted_login_dialog = True
     self.google_provider.save()
     params = [("next", "/courses/something/")]
     response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html")
     self.assertRedirects(
         response,
         expected_redirect_url('auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry)),
         target_status_code=302
     )
Ejemplo n.º 11
0
 def test_registration_page_bypass(self):
     """
     This tests to make sure when immediate signup is on that
     the user doesn't get presented with the registration page.
     """
     response = self.client.get(
         reverse('register_user'), follow=True,
         SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL))
     self.assertEquals((expected_redirect_url('/dashboard'), 302),
                       response.redirect_chain[-1])
     self.assertIn(SESSION_KEY, self.client.session)
Ejemplo n.º 12
0
 def test_settings_tpa_hinted_login_dialog_disabled(self, url_name, auth_entry):
     """Test that the dialog doesn't show up for hinted logins when disabled via settings.THIRD_PARTY_AUTH_HINT. """
     self.google_provider.skip_hinted_login_dialog = True
     self.google_provider.save()
     params = [("next", "/courses/something/")]
     response = self.client.get(reverse(url_name), params, HTTP_ACCEPT="text/html")
     self.assertRedirects(
         response,
         expected_redirect_url('auth/login/google-oauth2/?auth_entry={}&next=%2Fcourses%2Fsomething%2F%3Ftpa_hint%3Doa2-google-oauth2'.format(auth_entry)),
         target_status_code=302
     )
Ejemplo n.º 13
0
 def test_login_before_metadata_fetched(self):
     self._configure_testshib_provider(fetch_metadata=False)
     # The user goes to the login page, and sees a button to login with TestShib:
     testshib_login_url = self._check_login_page()
     # The user clicks on the TestShib button:
     try_login_response = self.client.get(testshib_login_url)
     # The user should be redirected to back to the login page:
     self.assertEqual(try_login_response.status_code, 302)
     self.assertEqual(try_login_response['Location'], expected_redirect_url(self.login_page_url, hostname=self.hostname))
     # When loading the login page, the user will see an error message:
     response = self.client.get(self.login_page_url)
     self.assertEqual(response.status_code, 200)
     self.assertIn('Authentication with TestShib is currently unavailable.', response.content)
Ejemplo n.º 14
0
 def test_login_before_metadata_fetched(self):
     self._configure_testshib_provider(fetch_metadata=False)
     # The user goes to the login page, and sees a button to login with TestShib:
     testshib_login_url = self._check_login_page()
     # The user clicks on the TestShib button:
     try_login_response = self.client.get(testshib_login_url)
     # The user should be redirected to back to the login page:
     self.assertEqual(try_login_response.status_code, 302)
     self.assertEqual(try_login_response['Location'], expected_redirect_url(self.login_page_url, hostname=self.hostname))
     # When loading the login page, the user will see an error message:
     response = self.client.get(self.login_page_url)
     self.assertEqual(response.status_code, 200)
     self.assertIn('Authentication with TestShib is currently unavailable.', response.content)
Ejemplo n.º 15
0
    def test_default_login_decorator_ssl(self):
        """
        Make sure that SSL login happens if it is enabled on protected
        views instead of showing the login form.
        """
        response = self.client.get(reverse('dashboard'), follows=True)
        self.assertEqual(response.status_code, 302)
        self.assertIn(reverse('signin_user'), response['location'])

        response = self.client.get(
            reverse('dashboard'), follow=True,
            SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL))
        self.assertEquals((expected_redirect_url('/dashboard'), 302),
                          response.redirect_chain[-1])
        self.assertIn(SESSION_KEY, self.client.session)
Ejemplo n.º 16
0
    def test_shib_login_enrollment(self):
        """
            A functionality test that a student with an existing shib login
            can auto-enroll in a class with GET or POST params.  Also tests the direction functionality of
            the 'next' GET/POST param
        """
        student = UserFactory.create()
        extauth = ExternalAuthMap(
            external_id='*****@*****.**',
            external_email='',
            external_domain='shib:https://idp.stanford.edu/',
            external_credentials="",
            internal_password="******",
            user=student)
        student.set_password("password")
        student.save()
        extauth.save()

        course = CourseFactory.create(
            org='Stanford',
            number='123',
            display_name='Shib Only',
            enrollment_domain='shib:https://idp.stanford.edu/',
            user_id=self.test_user_id,
        )

        # use django test client for sessions and url processing
        # no enrollment before trying
        self.assertFalse(CourseEnrollment.is_enrolled(student, course.id))
        self.client.logout()
        params = [('course_id', text_type(course.id)),
                  ('enrollment_action', 'enroll'), ('next', '/testredirect')]
        request_kwargs = {
            'path': '/shib-login/',
            'data': dict(params),
            'follow': False,
            'REMOTE_USER': '******',
            'Shib-Identity-Provider': 'https://idp.stanford.edu/',
            'HTTP_ACCEPT': "text/html"
        }
        response = self.client.get(**request_kwargs)
        # successful login is a redirect to the URL that handles auto-enrollment
        self.assertEqual(response.status_code, 302)
        self.assertEqual(
            response['location'],
            expected_redirect_url('/account/finish_auth?{}'.format(
                urlencode(params))))
Ejemplo n.º 17
0
    def test_shib_login_enrollment(self):
        """
            A functionality test that a student with an existing shib login
            can auto-enroll in a class with GET or POST params.  Also tests the direction functionality of
            the 'next' GET/POST param
        """
        student = UserFactory.create()
        extauth = ExternalAuthMap(external_id='*****@*****.**',
                                  external_email='',
                                  external_domain='shib:https://idp.stanford.edu/',
                                  external_credentials="",
                                  internal_password="******",
                                  user=student)
        student.set_password("password")
        student.save()
        extauth.save()

        course = CourseFactory.create(
            org='Stanford',
            number='123',
            display_name='Shib Only',
            enrollment_domain='shib:https://idp.stanford.edu/',
            user_id=self.test_user_id,
        )

        # use django test client for sessions and url processing
        # no enrollment before trying
        self.assertFalse(CourseEnrollment.is_enrolled(student, course.id))
        self.client.logout()
        params = [
            ('course_id', text_type(course.id)),
            ('enrollment_action', 'enroll'),
            ('next', '/testredirect')
        ]
        request_kwargs = {'path': '/shib-login/',
                          'data': dict(params),
                          'follow': False,
                          'REMOTE_USER': '******',
                          'Shib-Identity-Provider': 'https://idp.stanford.edu/',
                          'HTTP_ACCEPT': "text/html"}
        response = self.client.get(**request_kwargs)
        # successful login is a redirect to the URL that handles auto-enrollment
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['location'],
                         expected_redirect_url('/account/finish_auth?{}'.format(urlencode(params))))
Ejemplo n.º 18
0
    def test_signin_page_bypass(self):
        """
        This tests to make sure when ssl authentication is on
        that user doesn't get presented with the login page if they
        have a certificate.
        """
        # Test that they do signin if they don't have a cert
        response = self.client.get(reverse('signin_user'))
        self.assertEqual(200, response.status_code)
        self.assertIn('login-and-registration-container', response.content)

        # And get directly logged in otherwise
        response = self.client.get(
            reverse('signin_user'), follow=True,
            SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL))
        self.assertEquals((expected_redirect_url('/dashboard'), 302),
                          response.redirect_chain[-1])
        self.assertIn(SESSION_KEY, self.client.session)
Ejemplo n.º 19
0
    def create_course_page(self, course):
        """
        Test that loading the course wiki page creates the wiki page.
        The user must be enrolled in the course to see the page.
        """

        course_wiki_home = reverse('course_wiki', kwargs={'course_id': text_type(course.id)})
        referer = reverse("progress", kwargs={'course_id': text_type(course.id)})

        resp = self.client.get(course_wiki_home, follow=True, HTTP_REFERER=referer)

        course_wiki_page = referer.replace('progress', 'wiki/' + course.wiki_slug + "/")

        ending_location = resp.redirect_chain[-1][0]

        self.assertEquals(ending_location, expected_redirect_url(course_wiki_page))
        self.assertEquals(resp.status_code, 200)

        self.has_course_navigator(resp)
        self.assertContains(resp, '<h3 class="entry-title">{}</h3>'.format(course.display_name_with_default))
Ejemplo n.º 20
0
    def test_ssl_logout(self):
        """
        Because the branding view is cached for anonymous users and we
        use that to login users, the browser wasn't actually making the
        request to that view as the redirect was being cached. This caused
        a redirect loop, and this test confirms that that won't happen.

        Test is only in LMS because we don't use / in studio to login SSL users.
        """
        response = self.client.get(
            reverse('dashboard'), follow=True,
            SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL))
        self.assertEquals((expected_redirect_url('/dashboard'), 302),
                          response.redirect_chain[-1])
        self.assertIn(SESSION_KEY, self.client.session)
        response = self.client.get(
            reverse('logout'), follow=True,
            SSL_CLIENT_S_DN=self.AUTH_DN.format(self.USER_NAME, self.USER_EMAIL)
        )
        # Make sure that even though we logged out, we have logged back in
        self.assertIn(SESSION_KEY, self.client.session)
Ejemplo n.º 21
0
    def test_custom_form_error(self):
        """
        Use the Google provider to test the custom login/register failure redirects.
        """
        # The pipeline starts by a user GETting /auth/login/google-oauth2/?auth_entry=custom1
        # Synthesize that request and check that it redirects to the correct
        # provider page.
        auth_entry = 'custom1'  # See definition in lms/envs/test.py
        login_url = pipeline.get_login_url(self.provider.provider_id, auth_entry)
        login_url += "&next=/misc/final-destination"
        self.assert_redirect_to_provider_looks_correct(self.client.get(login_url))

        def fake_auth_complete_error(_inst, *_args, **_kwargs):
            """ Mock the backend's auth_complete() method """
            raise AuthException("Mock login failed")

        # Next, the provider makes a request against /auth/complete/<provider>.
        complete_url = pipeline.get_complete_url(self.provider.backend_name)
        with patch.object(self.provider.backend_class, 'auth_complete', fake_auth_complete_error):
            response = self.client.get(complete_url)
        # This should redirect to the custom error URL
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['Location'], expected_redirect_url('/misc/my-custom-sso-error-page', hostname='example.none'))
Ejemplo n.º 22
0
    def test_custom_form(self):
        """
        Use the Google provider to test the custom login/register form feature.
        """
        # The pipeline starts by a user GETting /auth/login/google-oauth2/?auth_entry=custom1
        # Synthesize that request and check that it redirects to the correct
        # provider page.
        auth_entry = 'custom1'  # See definition in lms/envs/test.py
        login_url = pipeline.get_login_url(self.provider.provider_id, auth_entry)
        login_url += "&next=/misc/final-destination"
        self.assert_redirect_to_provider_looks_correct(self.client.get(login_url))

        def fake_auth_complete(inst, *args, **kwargs):
            """ Mock the backend's auth_complete() method """
            kwargs.update({'response': self.get_response_data(), 'backend': inst})
            return inst.strategy.authenticate(*args, **kwargs)

        # Next, the provider makes a request against /auth/complete/<provider>.
        complete_url = pipeline.get_complete_url(self.provider.backend_name)
        with patch.object(self.provider.backend_class, 'auth_complete', fake_auth_complete):
            response = self.client.get(complete_url)
        # This should redirect to the custom login/register form:
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['Location'], expected_redirect_url('/auth/custom_auth_entry', hostname='example.none'))

        response = self.client.get(response['Location'])
        self.assertEqual(response.status_code, 200)
        self.assertIn('action="/misc/my-custom-registration-form" method="post"', response.content)
        data_decoded = base64.b64decode(response.context['data'])  # pylint: disable=no-member
        data_parsed = json.loads(data_decoded)
        # The user's details get passed to the custom page as a base64 encoded query parameter:
        self.assertEqual(data_parsed, {
            'auth_entry': 'custom1',
            'backend_name': 'google-oauth2',
            'provider_id': 'oa2-google-oauth2',
            'user_details': {
                'username': '******',
                'email': '*****@*****.**',
                'fullname': 'name_value',
                'first_name': 'given_name_value',
                'last_name': 'family_name_value',
            },
        })
        # Check the hash that is used to confirm the user's data in the GET parameter is correct
        secret_key = settings.THIRD_PARTY_AUTH_CUSTOM_AUTH_FORMS['custom1']['secret_key']
        hmac_expected = hmac.new(secret_key, msg=data_decoded, digestmod=hashlib.sha256).digest()
        self.assertEqual(base64.b64decode(response.context['hmac']), hmac_expected)  # pylint: disable=no-member

        # Now our custom registration form creates or logs in the user:
        email, password = data_parsed['user_details']['email'], 'random_password'
        created_user = UserFactory(email=email, password=password)
        login_response = self.client.post(reverse('login'), {'email': email, 'password': password})
        self.assertEqual(login_response.status_code, 200)

        # Now our custom login/registration page must resume the pipeline:
        response = self.client.get(complete_url)
        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['Location'], expected_redirect_url('/misc/final-destination', hostname='example.none'))

        _, strategy = self.get_request_and_strategy()
        self.assert_social_auth_exists_for_user(created_user, strategy)
    def test_lti_login(self):
        # The user initiates a login from an external site
        (uri, _headers, body) = self.lti.sign(
            uri=self.url_prefix + LTI_TPA_LOGIN_URL,
            http_method='POST',
            headers={'Content-Type': FORM_ENCODED},
            body={
                'user_id':
                LTI_USER_ID,
                'custom_tpa_next':
                '/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll',
            })
        login_response = self.client.post(path=uri,
                                          content_type=FORM_ENCODED,
                                          data=body)
        # The user should be redirected to the registration form
        self.assertEqual(login_response.status_code, 302)
        self.assertTrue(login_response['Location'].endswith(
            reverse('signin_user')))
        register_response = self.client.get(login_response['Location'])
        self.assertEqual(register_response.status_code, 200)
        self.assertIn('"currentProvider": "LTI Test Tool Consumer"',
                      register_response.content)
        self.assertIn('"errorMessage": null', register_response.content)

        # Now complete the form:
        ajax_register_response = self.client.post(
            reverse('user_api_registration'), {
                'email': EMAIL,
                'name': 'Myself',
                'username': EDX_USER_ID,
                'honor_code': True,
            })
        self.assertEqual(ajax_register_response.status_code, 200)
        continue_response = self.client.get(self.url_prefix +
                                            LTI_TPA_COMPLETE_URL)
        # The user should be redirected to the finish_auth view which will enroll them.
        # FinishAuthView.js reads the URL parameters directly from $.url
        self.assertEqual(continue_response.status_code, 302)
        self.assertEqual(
            continue_response['Location'],
            expected_redirect_url(
                '/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll'
            ))

        # Now check that we can login again
        self.client.logout()
        self.verify_user_email(EMAIL)
        (uri, _headers,
         body) = self.lti.sign(uri=self.url_prefix + LTI_TPA_LOGIN_URL,
                               http_method='POST',
                               headers={'Content-Type': FORM_ENCODED},
                               body={'user_id': LTI_USER_ID})
        login_2_response = self.client.post(path=uri,
                                            content_type=FORM_ENCODED,
                                            data=body)
        # The user should be redirected to the dashboard
        self.assertEqual(login_2_response.status_code, 302)
        expected_url = expected_redirect_url(LTI_TPA_COMPLETE_URL)
        # TODO: Remove Django 1.11 upgrade shim
        # SHIM: Get rid of this logic post-upgrade
        if django.VERSION >= (1, 9):
            expected_url = "{}?".format(expected_url)
        self.assertEqual(login_2_response['Location'], expected_url)
        continue_2_response = self.client.get(login_2_response['Location'])
        self.assertEqual(continue_2_response.status_code, 302)
        self.assertTrue(continue_2_response['Location'].endswith(
            reverse('dashboard')))

        # Check that the user was created correctly
        user = User.objects.get(email=EMAIL)
        self.assertEqual(user.username, EDX_USER_ID)
Ejemplo n.º 24
0
    def test_lti_login(self):
        # The user initiates a login from an external site
        (uri, _headers, body) = self.lti.sign(
            uri=self.url_prefix + LTI_TPA_LOGIN_URL, http_method='POST',
            headers={'Content-Type': FORM_ENCODED},
            body={
                'user_id': LTI_USER_ID,
                'custom_tpa_next': '/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll',
            }
        )
        login_response = self.client.post(path=uri, content_type=FORM_ENCODED, data=body)
        # The user should be redirected to the registration form
        self.assertEqual(login_response.status_code, 302)
        self.assertTrue(login_response['Location'].endswith(reverse('signin_user')))
        register_response = self.client.get(login_response['Location'])
        self.assertEqual(register_response.status_code, 200)
        self.assertIn('"currentProvider": "LTI Test Tool Consumer"', register_response.content)
        self.assertIn('"errorMessage": null', register_response.content)

        # Now complete the form:
        ajax_register_response = self.client.post(
            reverse('user_api_registration'),
            {
                'email': EMAIL,
                'name': 'Myself',
                'username': EDX_USER_ID,
                'honor_code': True,
            }
        )
        self.assertEqual(ajax_register_response.status_code, 200)
        continue_response = self.client.get(self.url_prefix + LTI_TPA_COMPLETE_URL)
        # The user should be redirected to the finish_auth view which will enroll them.
        # FinishAuthView.js reads the URL parameters directly from $.url
        self.assertEqual(continue_response.status_code, 302)
        self.assertEqual(
            continue_response['Location'],
            expected_redirect_url('/account/finish_auth/?course_id=my_course_id&enrollment_action=enroll')
        )

        # Now check that we can login again
        self.client.logout()
        self.verify_user_email(EMAIL)
        (uri, _headers, body) = self.lti.sign(
            uri=self.url_prefix + LTI_TPA_LOGIN_URL, http_method='POST',
            headers={'Content-Type': FORM_ENCODED},
            body={'user_id': LTI_USER_ID}
        )
        login_2_response = self.client.post(path=uri, content_type=FORM_ENCODED, data=body)
        # The user should be redirected to the dashboard
        self.assertEqual(login_2_response.status_code, 302)
        expected_url = expected_redirect_url(LTI_TPA_COMPLETE_URL)
        # TODO: Remove Django 1.11 upgrade shim
        # SHIM: Get rid of this logic post-upgrade
        if django.VERSION >= (1, 9):
            expected_url = "{}?".format(expected_url)
        self.assertEqual(login_2_response['Location'], expected_url)
        continue_2_response = self.client.get(login_2_response['Location'])
        self.assertEqual(continue_2_response.status_code, 302)
        self.assertTrue(continue_2_response['Location'].endswith(reverse('dashboard')))

        # Check that the user was created correctly
        user = User.objects.get(email=EMAIL)
        self.assertEqual(user.username, EDX_USER_ID)