diff --git a/netbox/netbox/tests/test_authentication.py b/netbox/netbox/tests/test_authentication.py index bd7d41186..e33e72f5d 100644 --- a/netbox/netbox/tests/test_authentication.py +++ b/netbox/netbox/tests/test_authentication.py @@ -94,30 +94,46 @@ class TokenAuthenticationTestCase(APITestCase): @override_settings(LOGIN_REQUIRED=True, EXEMPT_VIEW_PERMISSIONS=['*']) def test_token_write_enabled(self): url = reverse('dcim-api:site-list') - data = { - 'name': 'Site 1', - 'slug': 'site-1', - } + data = [ + { + 'name': 'Site 1', + 'slug': 'site-1', + }, + { + 'name': 'Site 2', + 'slug': 'site-2', + }, + ] + self.add_permissions('dcim.view_site', 'dcim.add_site') # Create v1 & v2 tokens token1 = Token.objects.create(version=1, user=self.user, write_enabled=False) token2 = Token.objects.create(version=2, user=self.user, write_enabled=False) - # Request with a write-disabled token should fail - response = self.client.post(url, data, format='json', HTTP_AUTHORIZATION=f'Token {token1.token}') + token1_header = f'Token {token1.token}' + token2_header = f'Bearer {token2.key}.{token2.token}' + + # GET request with a write-disabled token should succeed + response = self.client.get(url, HTTP_AUTHORIZATION=token1_header) + self.assertEqual(response.status_code, 200) + response = self.client.get(url, HTTP_AUTHORIZATION=token2_header) + self.assertEqual(response.status_code, 200) + + # POST request with a write-disabled token should fail + response = self.client.post(url, data[0], format='json', HTTP_AUTHORIZATION=token1_header) self.assertEqual(response.status_code, 403) - response = self.client.post(url, data, format='json', HTTP_AUTHORIZATION=f'Bearer {token2.key}.{token2.token}') + response = self.client.post(url, data[1], format='json', HTTP_AUTHORIZATION=token2_header) self.assertEqual(response.status_code, 403) - # Request with a write-enabled token should succeed + # POST request with a write-enabled token should succeed token1.write_enabled = True token1.save() token2.write_enabled = True token2.save() - response = self.client.post(url, data, format='json', HTTP_AUTHORIZATION=f'Token {token1.token}') - self.assertEqual(response.status_code, 403) - response = self.client.post(url, data, format='json', HTTP_AUTHORIZATION=f'Bearer {token2.key}.{token2.token}') - self.assertEqual(response.status_code, 403) + response = self.client.post(url, data[0], format='json', HTTP_AUTHORIZATION=token1_header) + self.assertEqual(response.status_code, 201) + response = self.client.post(url, data[1], format='json', HTTP_AUTHORIZATION=token2_header) + self.assertEqual(response.status_code, 201) @override_settings(LOGIN_REQUIRED=True, EXEMPT_VIEW_PERMISSIONS=['*']) def test_token_allowed_ips(self): diff --git a/netbox/users/tests/test_api.py b/netbox/users/tests/test_api.py index f0218179a..741c578b6 100644 --- a/netbox/users/tests/test_api.py +++ b/netbox/users/tests/test_api.py @@ -2,6 +2,7 @@ from django.test import override_settings from django.urls import reverse from core.models import ObjectType +from users.constants import TOKEN_DEFAULT_LENGTH from users.models import Group, ObjectPermission, Token, User from utilities.data import deepmerge from utilities.testing import APIViewTestCases, APITestCase, create_test_user @@ -257,7 +258,7 @@ class TokenTest( response = self.client.post(url, data, format='json', **self.header) self.assertEqual(response.status_code, 201) self.assertIn('token', response.data) - self.assertEqual(len(response.data['token']), 40) + self.assertEqual(len(response.data['token']), TOKEN_DEFAULT_LENGTH) self.assertEqual(response.data['description'], data['description']) self.assertEqual(response.data['expires'], data['expires']) token = Token.objects.get(user=user) diff --git a/netbox/users/tests/test_views.py b/netbox/users/tests/test_views.py index 0395c2209..24aec6941 100644 --- a/netbox/users/tests/test_views.py +++ b/netbox/users/tests/test_views.py @@ -240,9 +240,9 @@ class TokenTestCase( cls.csv_data = ( "token,user,description", - f"123456789012345678901234567890123456789A,{users[0].pk},Test token", - f"123456789012345678901234567890123456789B,{users[1].pk},Test token", - f"123456789012345678901234567890123456789C,{users[1].pk},Test token", + f"zjebxBPzICiPbWz0Wtx0fTL7bCKXKGTYhNzkgC2S,{users[0].pk},Test token", + f"9Z5kGtQWba60Vm226dPDfEAV6BhlTr7H5hAXAfbF,{users[1].pk},Test token", + f"njpMnNT6r0k0MDccoUhTYYlvP9BvV3qLzYN2p6Uu,{users[1].pk},Test token", ) cls.csv_update_data = ( diff --git a/netbox/utilities/testing/views.py b/netbox/utilities/testing/views.py index c054dc5a2..f00b21d08 100644 --- a/netbox/utilities/testing/views.py +++ b/netbox/utilities/testing/views.py @@ -240,12 +240,10 @@ class ViewTestCases: :form_data: Data to be used when updating the first existing object. """ form_data = {} - form_edit_data = {} validation_excluded_fields = [] def test_edit_object_without_permission(self): instance = self._get_queryset().first() - form_data = self.form_edit_data or self.form_data # Try GET without permission with disable_warnings('django.request'): @@ -254,7 +252,7 @@ class ViewTestCases: # Try POST without permission request = { 'path': self._get_url('edit', instance), - 'data': post_data(form_data), + 'data': post_data(self.form_data), } with disable_warnings('django.request'): self.assertHttpStatus(self.client.post(**request), 403) @@ -262,7 +260,6 @@ class ViewTestCases: @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[]) def test_edit_object_with_permission(self): instance = self._get_queryset().first() - form_data = self.form_edit_data or self.form_data # Assign model-level permission obj_perm = ObjectPermission( @@ -278,21 +275,21 @@ class ViewTestCases: # Add custom field data if the model supports it if issubclass(self.model, CustomFieldsMixin): - add_custom_field_data(form_data, self.model) + add_custom_field_data(self.form_data, self.model) # If supported, add a changelog message if issubclass(self.model, ChangeLoggingMixin): - if 'changelog_message' not in form_data: - form_data['changelog_message'] = get_random_string(10) + if 'changelog_message' not in self.form_data: + self.form_data['changelog_message'] = get_random_string(10) # Try POST with model-level permission request = { 'path': self._get_url('edit', instance), - 'data': post_data(form_data), + 'data': post_data(self.form_data), } self.assertHttpStatus(self.client.post(**request), 302) instance = self._get_queryset().get(pk=instance.pk) - self.assertInstanceEqual(instance, form_data, exclude=self.validation_excluded_fields) + self.assertInstanceEqual(instance, self.form_data, exclude=self.validation_excluded_fields) # Verify ObjectChange creation if issubclass(self.model, ChangeLoggingMixin): @@ -302,12 +299,11 @@ class ViewTestCases: ) self.assertEqual(len(objectchanges), 1) self.assertEqual(objectchanges[0].action, ObjectChangeActionChoices.ACTION_UPDATE) - self.assertEqual(objectchanges[0].message, form_data['changelog_message']) + self.assertEqual(objectchanges[0].message, self.form_data['changelog_message']) @override_settings(EXEMPT_VIEW_PERMISSIONS=['*'], EXEMPT_EXCLUDE_MODELS=[]) def test_edit_object_with_constrained_permission(self): instance1, instance2 = self._get_queryset().all()[:2] - form_data = self.form_edit_data or self.form_data # Assign constrained permission obj_perm = ObjectPermission( @@ -328,16 +324,16 @@ class ViewTestCases: # Try to edit a permitted object request = { 'path': self._get_url('edit', instance1), - 'data': post_data(form_data), + 'data': post_data(self.form_data), } self.assertHttpStatus(self.client.post(**request), 302) instance = self._get_queryset().get(pk=instance1.pk) - self.assertInstanceEqual(instance, form_data, exclude=self.validation_excluded_fields) + self.assertInstanceEqual(instance, self.form_data, exclude=self.validation_excluded_fields) # Try to edit a non-permitted object request = { 'path': self._get_url('edit', instance2), - 'data': post_data(form_data), + 'data': post_data(self.form_data), } self.assertHttpStatus(self.client.post(**request), 404)