class SessionAuthTests(TestCase):
    """User session authentication"""
    urls = 'tests.test_authentication'

    def setUp(self):
        self.csrf_client = APIClient(enforce_csrf_checks=True)
        self.non_csrf_client = APIClient(enforce_csrf_checks=False)
        self.username = '******'
        self.email = '*****@*****.**'
        self.password = '******'
        self.user = User.objects.create_user(self.username, self.email, self.password)

    def tearDown(self):
        self.csrf_client.logout()

    def test_login_view_renders_on_get(self):
        """
        Ensure the login template renders for a basic GET.

        cf. [#1810](https://github.com/tomchristie/django-rest-framework/pull/1810)
        """
        response = self.csrf_client.get('/auth/login/')
        self.assertContains(response, '<label for="id_username">Username:</label>')

    def test_post_form_session_auth_failing_csrf(self):
        """
        Ensure POSTing form over session authentication without CSRF token fails.
        """
        self.csrf_client.login(username=self.username, password=self.password)
        response = self.csrf_client.post('/session/', {'example': 'example'})
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_post_form_session_auth_passing(self):
        """
        Ensure POSTing form over session authentication with logged in user and CSRF token passes.
        """
        self.non_csrf_client.login(username=self.username, password=self.password)
        response = self.non_csrf_client.post('/session/', {'example': 'example'})
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_put_form_session_auth_passing(self):
        """
        Ensure PUTting form over session authentication with logged in user and CSRF token passes.
        """
        self.non_csrf_client.login(username=self.username, password=self.password)
        response = self.non_csrf_client.put('/session/', {'example': 'example'})
        self.assertEqual(response.status_code, status.HTTP_200_OK)

    def test_post_form_session_auth_failing(self):
        """
        Ensure POSTing form over session authentication without logged in user fails.
        """
        response = self.csrf_client.post('/session/', {'example': 'example'})
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
class TestAPITestClient(TestCase):
    urls = 'tests.test_testing'

    def setUp(self):
        self.client = APIClient()

    def test_credentials(self):
        """
        Setting `.credentials()` adds the required headers to each request.
        """
        self.client.credentials(HTTP_AUTHORIZATION='example')
        for _ in range(0, 3):
            response = self.client.get('/view/')
            self.assertEqual(response.data['auth'], 'example')

    def test_force_authenticate(self):
        """
        Setting `.force_authenticate()` forcibly authenticates each request.
        """
        user = User.objects.create_user('example', '*****@*****.**')
        self.client.force_authenticate(user)
        response = self.client.get('/view/')
        self.assertEqual(response.data['user'], 'example')

    def test_force_authenticate_with_sessions(self):
        """
        Setting `.force_authenticate()` forcibly authenticates each request.
        """
        user = User.objects.create_user('example', '*****@*****.**')
        self.client.force_authenticate(user)

        # First request does not yet have an active session
        response = self.client.get('/session-view/')
        self.assertEqual(response.data['active_session'], False)

        # Subsequant requests have an active session
        response = self.client.get('/session-view/')
        self.assertEqual(response.data['active_session'], True)

        # Force authenticating as `None` should also logout the user session.
        self.client.force_authenticate(None)
        response = self.client.get('/session-view/')
        self.assertEqual(response.data['active_session'], False)

    def test_csrf_exempt_by_default(self):
        """
        By default, the test client is CSRF exempt.
        """
        User.objects.create_user('example', '*****@*****.**', 'password')
        self.client.login(username='******', password='******')
        response = self.client.post('/view/')
        self.assertEqual(response.status_code, 200)

    def test_explicitly_enforce_csrf_checks(self):
        """
        The test client can enforce CSRF checks.
        """
        client = APIClient(enforce_csrf_checks=True)
        User.objects.create_user('example', '*****@*****.**', 'password')
        client.login(username='******', password='******')
        response = client.post('/view/')
        expected = {'detail': 'CSRF Failed: CSRF cookie not set.'}
        self.assertEqual(response.status_code, 403)
        self.assertEqual(response.data, expected)

    def test_can_logout(self):
        """
        `logout()` resets stored credentials
        """
        self.client.credentials(HTTP_AUTHORIZATION='example')
        response = self.client.get('/view/')
        self.assertEqual(response.data['auth'], 'example')
        self.client.logout()
        response = self.client.get('/view/')
        self.assertEqual(response.data['auth'], b'')

    def test_logout_resets_force_authenticate(self):
        """
        `logout()` resets any `force_authenticate`
        """
        user = User.objects.create_user('example', '*****@*****.**', 'password')
        self.client.force_authenticate(user)
        response = self.client.get('/view/')
        self.assertEqual(response.data['user'], 'example')
        self.client.logout()
        response = self.client.get('/view/')
        self.assertEqual(response.data['user'], '')

    def test_follow_redirect(self):
        """
        Follow redirect by setting follow argument.
        """
        response = self.client.get('/redirect-view/')
        self.assertEqual(response.status_code, 302)
        response = self.client.get('/redirect-view/', follow=True)
        self.assertIsNotNone(response.redirect_chain)
        self.assertEqual(response.status_code, 200)

        response = self.client.post('/redirect-view/')
        self.assertEqual(response.status_code, 302)
        response = self.client.post('/redirect-view/', follow=True)
        self.assertIsNotNone(response.redirect_chain)
        self.assertEqual(response.status_code, 200)

        response = self.client.put('/redirect-view/')
        self.assertEqual(response.status_code, 302)
        response = self.client.put('/redirect-view/', follow=True)
        self.assertIsNotNone(response.redirect_chain)
        self.assertEqual(response.status_code, 200)

        response = self.client.patch('/redirect-view/')
        self.assertEqual(response.status_code, 302)
        response = self.client.patch('/redirect-view/', follow=True)
        self.assertIsNotNone(response.redirect_chain)
        self.assertEqual(response.status_code, 200)

        response = self.client.delete('/redirect-view/')
        self.assertEqual(response.status_code, 302)
        response = self.client.delete('/redirect-view/', follow=True)
        self.assertIsNotNone(response.redirect_chain)
        self.assertEqual(response.status_code, 200)

        response = self.client.options('/redirect-view/')
        self.assertEqual(response.status_code, 302)
        response = self.client.options('/redirect-view/', follow=True)
        self.assertIsNotNone(response.redirect_chain)
        self.assertEqual(response.status_code, 200)