mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-06-18 20:43:29 +03:00
parent
8e2787fd4b
commit
dc09eef24a
|
@ -16,7 +16,11 @@ class DropdownWithAuthTests(TestCase):
|
||||||
self.username = 'john'
|
self.username = 'john'
|
||||||
self.email = 'lennon@thebeatles.com'
|
self.email = 'lennon@thebeatles.com'
|
||||||
self.password = 'password'
|
self.password = 'password'
|
||||||
self.user = User.objects.create_user(self.username, self.email, self.password)
|
self.user = User.objects.create_user(
|
||||||
|
self.username,
|
||||||
|
self.email,
|
||||||
|
self.password
|
||||||
|
)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
@ -46,7 +50,11 @@ class NoDropdownWithoutAuthTests(TestCase):
|
||||||
self.username = 'john'
|
self.username = 'john'
|
||||||
self.email = 'lennon@thebeatles.com'
|
self.email = 'lennon@thebeatles.com'
|
||||||
self.password = 'password'
|
self.password = 'password'
|
||||||
self.user = User.objects.create_user(self.username, self.email, self.password)
|
self.user = User.objects.create_user(
|
||||||
|
self.username,
|
||||||
|
self.email,
|
||||||
|
self.password
|
||||||
|
)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.client.logout()
|
self.client.logout()
|
||||||
|
|
|
@ -17,7 +17,11 @@ class RESTFrameworkModel(models.Model):
|
||||||
|
|
||||||
|
|
||||||
class BasicModel(RESTFrameworkModel):
|
class BasicModel(RESTFrameworkModel):
|
||||||
text = models.CharField(max_length=100, verbose_name=_("Text comes here"), help_text=_("Text description."))
|
text = models.CharField(
|
||||||
|
max_length=100,
|
||||||
|
verbose_name=_("Text comes here"),
|
||||||
|
help_text=_("Text description.")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseFilterableItem(RESTFrameworkModel):
|
class BaseFilterableItem(RESTFrameworkModel):
|
||||||
|
@ -84,5 +88,6 @@ class OneToOneTarget(RESTFrameworkModel):
|
||||||
|
|
||||||
class NullableOneToOneSource(RESTFrameworkModel):
|
class NullableOneToOneSource(RESTFrameworkModel):
|
||||||
name = models.CharField(max_length=100)
|
name = models.CharField(max_length=100)
|
||||||
target = models.OneToOneField(OneToOneTarget, null=True, blank=True,
|
target = models.OneToOneField(
|
||||||
|
OneToOneTarget, null=True, blank=True,
|
||||||
related_name='nullable_source', on_delete=models.CASCADE)
|
related_name='nullable_source', on_delete=models.CASCADE)
|
||||||
|
|
|
@ -53,11 +53,28 @@ class MockView(APIView):
|
||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^session/$', MockView.as_view(authentication_classes=[SessionAuthentication])),
|
url(
|
||||||
url(r'^basic/$', MockView.as_view(authentication_classes=[BasicAuthentication])),
|
r'^session/$',
|
||||||
url(r'^token/$', MockView.as_view(authentication_classes=[TokenAuthentication])),
|
MockView.as_view(authentication_classes=[SessionAuthentication])
|
||||||
url(r'^customtoken/$', MockView.as_view(authentication_classes=[CustomTokenAuthentication])),
|
),
|
||||||
url(r'^customkeywordtoken/$', MockView.as_view(authentication_classes=[CustomKeywordTokenAuthentication])),
|
url(
|
||||||
|
r'^basic/$',
|
||||||
|
MockView.as_view(authentication_classes=[BasicAuthentication])
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^token/$',
|
||||||
|
MockView.as_view(authentication_classes=[TokenAuthentication])
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^customtoken/$',
|
||||||
|
MockView.as_view(authentication_classes=[CustomTokenAuthentication])
|
||||||
|
),
|
||||||
|
url(
|
||||||
|
r'^customkeywordtoken/$',
|
||||||
|
MockView.as_view(
|
||||||
|
authentication_classes=[CustomKeywordTokenAuthentication]
|
||||||
|
)
|
||||||
|
),
|
||||||
url(r'^auth-token/$', 'rest_framework.authtoken.views.obtain_auth_token'),
|
url(r'^auth-token/$', 'rest_framework.authtoken.views.obtain_auth_token'),
|
||||||
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
|
url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')),
|
||||||
]
|
]
|
||||||
|
@ -72,22 +89,37 @@ class BasicAuthTests(TestCase):
|
||||||
self.username = 'john'
|
self.username = 'john'
|
||||||
self.email = 'lennon@thebeatles.com'
|
self.email = 'lennon@thebeatles.com'
|
||||||
self.password = 'password'
|
self.password = 'password'
|
||||||
self.user = User.objects.create_user(self.username, self.email, self.password)
|
self.user = User.objects.create_user(
|
||||||
|
self.username, self.email, self.password
|
||||||
|
)
|
||||||
|
|
||||||
def test_post_form_passing_basic_auth(self):
|
def test_post_form_passing_basic_auth(self):
|
||||||
"""Ensure POSTing json over basic auth with correct credentials passes and does not require CSRF"""
|
"""Ensure POSTing json over basic auth with correct credentials passes and does not require CSRF"""
|
||||||
credentials = ('%s:%s' % (self.username, self.password))
|
credentials = ('%s:%s' % (self.username, self.password))
|
||||||
base64_credentials = base64.b64encode(credentials.encode(HTTP_HEADER_ENCODING)).decode(HTTP_HEADER_ENCODING)
|
base64_credentials = base64.b64encode(
|
||||||
|
credentials.encode(HTTP_HEADER_ENCODING)
|
||||||
|
).decode(HTTP_HEADER_ENCODING)
|
||||||
auth = 'Basic %s' % base64_credentials
|
auth = 'Basic %s' % base64_credentials
|
||||||
response = self.csrf_client.post('/basic/', {'example': 'example'}, HTTP_AUTHORIZATION=auth)
|
response = self.csrf_client.post(
|
||||||
|
'/basic/',
|
||||||
|
{'example': 'example'},
|
||||||
|
HTTP_AUTHORIZATION=auth
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_post_json_passing_basic_auth(self):
|
def test_post_json_passing_basic_auth(self):
|
||||||
"""Ensure POSTing form over basic auth with correct credentials passes and does not require CSRF"""
|
"""Ensure POSTing form over basic auth with correct credentials passes and does not require CSRF"""
|
||||||
credentials = ('%s:%s' % (self.username, self.password))
|
credentials = ('%s:%s' % (self.username, self.password))
|
||||||
base64_credentials = base64.b64encode(credentials.encode(HTTP_HEADER_ENCODING)).decode(HTTP_HEADER_ENCODING)
|
base64_credentials = base64.b64encode(
|
||||||
|
credentials.encode(HTTP_HEADER_ENCODING)
|
||||||
|
).decode(HTTP_HEADER_ENCODING)
|
||||||
auth = 'Basic %s' % base64_credentials
|
auth = 'Basic %s' % base64_credentials
|
||||||
response = self.csrf_client.post('/basic/', {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth)
|
response = self.csrf_client.post(
|
||||||
|
'/basic/',
|
||||||
|
{'example': 'example'},
|
||||||
|
format='json',
|
||||||
|
HTTP_AUTHORIZATION=auth
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_regression_handle_bad_base64_basic_auth_header(self):
|
def test_regression_handle_bad_base64_basic_auth_header(self):
|
||||||
|
@ -95,7 +127,12 @@ class BasicAuthTests(TestCase):
|
||||||
# regression test for issue in 'rest_framework.authentication.BasicAuthentication.authenticate'
|
# regression test for issue in 'rest_framework.authentication.BasicAuthentication.authenticate'
|
||||||
# https://github.com/tomchristie/django-rest-framework/issues/4089
|
# https://github.com/tomchristie/django-rest-framework/issues/4089
|
||||||
auth = 'Basic =a='
|
auth = 'Basic =a='
|
||||||
response = self.csrf_client.post('/basic/', {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth)
|
response = self.csrf_client.post(
|
||||||
|
'/basic/',
|
||||||
|
{'example': 'example'},
|
||||||
|
format='json',
|
||||||
|
HTTP_AUTHORIZATION=auth
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||||
|
|
||||||
def test_post_form_failing_basic_auth(self):
|
def test_post_form_failing_basic_auth(self):
|
||||||
|
@ -105,7 +142,11 @@ class BasicAuthTests(TestCase):
|
||||||
|
|
||||||
def test_post_json_failing_basic_auth(self):
|
def test_post_json_failing_basic_auth(self):
|
||||||
"""Ensure POSTing json over basic auth without correct credentials fails"""
|
"""Ensure POSTing json over basic auth without correct credentials fails"""
|
||||||
response = self.csrf_client.post('/basic/', {'example': 'example'}, format='json')
|
response = self.csrf_client.post(
|
||||||
|
'/basic/',
|
||||||
|
{'example': 'example'},
|
||||||
|
format='json'
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||||
self.assertEqual(response['WWW-Authenticate'], 'Basic realm="api"')
|
self.assertEqual(response['WWW-Authenticate'], 'Basic realm="api"')
|
||||||
|
|
||||||
|
@ -120,7 +161,9 @@ class SessionAuthTests(TestCase):
|
||||||
self.username = 'john'
|
self.username = 'john'
|
||||||
self.email = 'lennon@thebeatles.com'
|
self.email = 'lennon@thebeatles.com'
|
||||||
self.password = 'password'
|
self.password = 'password'
|
||||||
self.user = User.objects.create_user(self.username, self.email, self.password)
|
self.user = User.objects.create_user(
|
||||||
|
self.username, self.email, self.password
|
||||||
|
)
|
||||||
|
|
||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
self.csrf_client.logout()
|
self.csrf_client.logout()
|
||||||
|
@ -132,7 +175,9 @@ class SessionAuthTests(TestCase):
|
||||||
cf. [#1810](https://github.com/tomchristie/django-rest-framework/pull/1810)
|
cf. [#1810](https://github.com/tomchristie/django-rest-framework/pull/1810)
|
||||||
"""
|
"""
|
||||||
response = self.csrf_client.get('/auth/login/')
|
response = self.csrf_client.get('/auth/login/')
|
||||||
self.assertContains(response, '<label for="id_username">Username:</label>')
|
self.assertContains(
|
||||||
|
response, '<label for="id_username">Username:</label>'
|
||||||
|
)
|
||||||
|
|
||||||
def test_post_form_session_auth_failing_csrf(self):
|
def test_post_form_session_auth_failing_csrf(self):
|
||||||
"""
|
"""
|
||||||
|
@ -144,18 +189,28 @@ class SessionAuthTests(TestCase):
|
||||||
|
|
||||||
def test_post_form_session_auth_passing(self):
|
def test_post_form_session_auth_passing(self):
|
||||||
"""
|
"""
|
||||||
Ensure POSTing form over session authentication with logged in user and CSRF token passes.
|
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)
|
self.non_csrf_client.login(
|
||||||
response = self.non_csrf_client.post('/session/', {'example': 'example'})
|
username=self.username, password=self.password
|
||||||
|
)
|
||||||
|
response = self.non_csrf_client.post(
|
||||||
|
'/session/', {'example': 'example'}
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_put_form_session_auth_passing(self):
|
def test_put_form_session_auth_passing(self):
|
||||||
"""
|
"""
|
||||||
Ensure PUTting form over session authentication with logged in user and CSRF token passes.
|
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)
|
self.non_csrf_client.login(
|
||||||
response = self.non_csrf_client.put('/session/', {'example': 'example'})
|
username=self.username, password=self.password
|
||||||
|
)
|
||||||
|
response = self.non_csrf_client.put(
|
||||||
|
'/session/', {'example': 'example'}
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_post_form_session_auth_failing(self):
|
def test_post_form_session_auth_failing(self):
|
||||||
|
@ -178,52 +233,81 @@ class BaseTokenAuthTests(object):
|
||||||
self.username = 'john'
|
self.username = 'john'
|
||||||
self.email = 'lennon@thebeatles.com'
|
self.email = 'lennon@thebeatles.com'
|
||||||
self.password = 'password'
|
self.password = 'password'
|
||||||
self.user = User.objects.create_user(self.username, self.email, self.password)
|
self.user = User.objects.create_user(
|
||||||
|
self.username, self.email, self.password
|
||||||
|
)
|
||||||
|
|
||||||
self.key = 'abcd1234'
|
self.key = 'abcd1234'
|
||||||
self.token = self.model.objects.create(key=self.key, user=self.user)
|
self.token = self.model.objects.create(key=self.key, user=self.user)
|
||||||
|
|
||||||
def test_post_form_passing_token_auth(self):
|
def test_post_form_passing_token_auth(self):
|
||||||
"""Ensure POSTing json over token auth with correct credentials passes and does not require CSRF"""
|
"""
|
||||||
|
Ensure POSTing json over token auth with correct
|
||||||
|
credentials passes and does not require CSRF
|
||||||
|
"""
|
||||||
auth = self.header_prefix + self.key
|
auth = self.header_prefix + self.key
|
||||||
response = self.csrf_client.post(self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth)
|
response = self.csrf_client.post(
|
||||||
|
self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_fail_post_form_passing_nonexistent_token_auth(self):
|
def test_fail_post_form_passing_nonexistent_token_auth(self):
|
||||||
# use a nonexistent token key
|
# use a nonexistent token key
|
||||||
auth = self.header_prefix + 'wxyz6789'
|
auth = self.header_prefix + 'wxyz6789'
|
||||||
response = self.csrf_client.post(self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth)
|
response = self.csrf_client.post(
|
||||||
|
self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||||
|
|
||||||
def test_fail_post_form_passing_invalid_token_auth(self):
|
def test_fail_post_form_passing_invalid_token_auth(self):
|
||||||
# add an 'invalid' unicode character
|
# add an 'invalid' unicode character
|
||||||
auth = self.header_prefix + self.key + "¸"
|
auth = self.header_prefix + self.key + "¸"
|
||||||
response = self.csrf_client.post(self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth)
|
response = self.csrf_client.post(
|
||||||
|
self.path, {'example': 'example'}, HTTP_AUTHORIZATION=auth
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||||
|
|
||||||
def test_post_json_passing_token_auth(self):
|
def test_post_json_passing_token_auth(self):
|
||||||
"""Ensure POSTing form over token auth with correct credentials passes and does not require CSRF"""
|
"""
|
||||||
|
Ensure POSTing form over token auth with correct
|
||||||
|
credentials passes and does not require CSRF
|
||||||
|
"""
|
||||||
auth = self.header_prefix + self.key
|
auth = self.header_prefix + self.key
|
||||||
response = self.csrf_client.post(self.path, {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth)
|
response = self.csrf_client.post(
|
||||||
|
self.path, {'example': 'example'},
|
||||||
|
format='json', HTTP_AUTHORIZATION=auth
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
|
|
||||||
def test_post_json_makes_one_db_query(self):
|
def test_post_json_makes_one_db_query(self):
|
||||||
"""Ensure that authenticating a user using a token performs only one DB query"""
|
"""
|
||||||
|
Ensure that authenticating a user using a
|
||||||
|
token performs only one DB query
|
||||||
|
"""
|
||||||
auth = self.header_prefix + self.key
|
auth = self.header_prefix + self.key
|
||||||
|
|
||||||
def func_to_test():
|
def func_to_test():
|
||||||
return self.csrf_client.post(self.path, {'example': 'example'}, format='json', HTTP_AUTHORIZATION=auth)
|
return self.csrf_client.post(
|
||||||
|
self.path, {'example': 'example'},
|
||||||
|
format='json', HTTP_AUTHORIZATION=auth
|
||||||
|
)
|
||||||
|
|
||||||
self.assertNumQueries(1, func_to_test)
|
self.assertNumQueries(1, func_to_test)
|
||||||
|
|
||||||
def test_post_form_failing_token_auth(self):
|
def test_post_form_failing_token_auth(self):
|
||||||
"""Ensure POSTing form over token auth without correct credentials fails"""
|
"""
|
||||||
|
Ensure POSTing form over token auth without correct credentials fails
|
||||||
|
"""
|
||||||
response = self.csrf_client.post(self.path, {'example': 'example'})
|
response = self.csrf_client.post(self.path, {'example': 'example'})
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||||
|
|
||||||
def test_post_json_failing_token_auth(self):
|
def test_post_json_failing_token_auth(self):
|
||||||
"""Ensure POSTing json over token auth without correct credentials fails"""
|
"""
|
||||||
response = self.csrf_client.post(self.path, {'example': 'example'}, format='json')
|
Ensure POSTing json over token auth without correct credentials fails
|
||||||
|
"""
|
||||||
|
response = self.csrf_client.post(
|
||||||
|
self.path, {'example': 'example'}, format='json'
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||||
|
|
||||||
|
|
||||||
|
@ -246,16 +330,25 @@ class TokenAuthTests(BaseTokenAuthTests, TestCase):
|
||||||
def test_token_login_json(self):
|
def test_token_login_json(self):
|
||||||
"""Ensure token login view using JSON POST works."""
|
"""Ensure token login view using JSON POST works."""
|
||||||
client = APIClient(enforce_csrf_checks=True)
|
client = APIClient(enforce_csrf_checks=True)
|
||||||
response = client.post('/auth-token/',
|
response = client.post(
|
||||||
{'username': self.username, 'password': self.password}, format='json')
|
'/auth-token/',
|
||||||
|
{'username': self.username, 'password': self.password},
|
||||||
|
format='json'
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||||
self.assertEqual(response.data['token'], self.key)
|
self.assertEqual(response.data['token'], self.key)
|
||||||
|
|
||||||
def test_token_login_json_bad_creds(self):
|
def test_token_login_json_bad_creds(self):
|
||||||
"""Ensure token login view using JSON POST fails if bad credentials are used."""
|
"""
|
||||||
|
Ensure token login view using JSON POST fails if
|
||||||
|
bad credentials are used
|
||||||
|
"""
|
||||||
client = APIClient(enforce_csrf_checks=True)
|
client = APIClient(enforce_csrf_checks=True)
|
||||||
response = client.post('/auth-token/',
|
response = client.post(
|
||||||
{'username': self.username, 'password': "badpass"}, format='json')
|
'/auth-token/',
|
||||||
|
{'username': self.username, 'password': "badpass"},
|
||||||
|
format='json'
|
||||||
|
)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
|
||||||
def test_token_login_json_missing_fields(self):
|
def test_token_login_json_missing_fields(self):
|
||||||
|
|
Loading…
Reference in New Issue
Block a user