1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00
2024-04-02 16:33:12 -04:00

385 lines
12 KiB
Python

from django.contrib.auth import get_user_model
from django.urls import reverse
from core.models import ObjectType
from users.models import Group, ObjectPermission, Token
from utilities.data import deepmerge
from utilities.testing import APIViewTestCases, APITestCase, create_test_user
User = get_user_model()
class AppTest(APITestCase):
def test_root(self):
url = reverse('users-api:api-root')
response = self.client.get(f'{url}?format=api', **self.header)
self.assertEqual(response.status_code, 200)
class UserTest(APIViewTestCases.APIViewTestCase):
model = User
brief_fields = ['display', 'id', 'url', 'username']
validation_excluded_fields = ['password']
bulk_update_data = {
'email': 'test@example.com',
}
@classmethod
def setUpTestData(cls):
permissions = (
ObjectPermission(name='Permission 1', actions=['view']),
ObjectPermission(name='Permission 2', actions=['view']),
ObjectPermission(name='Permission 3', actions=['view']),
)
ObjectPermission.objects.bulk_create(permissions)
permissions[0].object_types.add(ObjectType.objects.get_by_natural_key('dcim', 'site'))
permissions[1].object_types.add(ObjectType.objects.get_by_natural_key('dcim', 'location'))
permissions[2].object_types.add(ObjectType.objects.get_by_natural_key('dcim', 'rack'))
users = (
User(username='User1', password='password1'),
User(username='User2', password='password2'),
User(username='User3', password='password3'),
)
User.objects.bulk_create(users)
cls.create_data = [
{
'username': 'User4',
'password': 'password4',
'permissions': [permissions[0].pk],
},
{
'username': 'User5',
'password': 'password5',
'permissions': [permissions[1].pk],
},
{
'username': 'User6',
'password': 'password6',
'permissions': [permissions[2].pk],
},
]
def test_that_password_is_changed(self):
"""
Test that password is changed
"""
obj_perm = ObjectPermission(
name='Test permission',
actions=['change']
)
obj_perm.save()
obj_perm.users.add(self.user)
obj_perm.object_types.add(ObjectType.objects.get_for_model(self.model))
user_credentials = {
'username': 'newuser',
'password': 'abc123',
}
user = User.objects.create_user(**user_credentials)
data = {
'password': 'newpassword'
}
url = reverse('users-api:user-detail', kwargs={'pk': user.id})
response = self.client.patch(url, data, format='json', **self.header)
self.assertEqual(response.status_code, 200)
user.refresh_from_db()
self.assertTrue(user.check_password(data['password']))
class GroupTest(APIViewTestCases.APIViewTestCase):
model = Group
brief_fields = ['description', 'display', 'id', 'name', 'url']
@classmethod
def setUpTestData(cls):
permissions = (
ObjectPermission(name='Permission 1', actions=['view']),
ObjectPermission(name='Permission 2', actions=['view']),
ObjectPermission(name='Permission 3', actions=['view']),
)
ObjectPermission.objects.bulk_create(permissions)
permissions[0].object_types.add(ObjectType.objects.get_by_natural_key('dcim', 'site'))
permissions[1].object_types.add(ObjectType.objects.get_by_natural_key('dcim', 'location'))
permissions[2].object_types.add(ObjectType.objects.get_by_natural_key('dcim', 'rack'))
groups = (
Group(name='Group 1'),
Group(name='Group 2'),
Group(name='Group 3'),
)
Group.objects.bulk_create(groups)
cls.create_data = [
{
'name': 'Group 4',
'permissions': [permissions[0].pk],
},
{
'name': 'Group 5',
'permissions': [permissions[1].pk],
},
{
'name': 'Group 6',
'permissions': [permissions[2].pk],
},
]
def model_to_dict(self, instance, *args, **kwargs):
# Overwrite permissions attr to work around the serializer field having a different name
data = super().model_to_dict(instance, *args, **kwargs)
data['permissions'] = list(instance.object_permissions.values_list('id', flat=True))
return data
def test_bulk_update_objects(self):
"""
Disabled test. There's no attribute we can set in bulk for Groups.
"""
return
class TokenTest(
# No GraphQL support for Token
APIViewTestCases.GetObjectViewTestCase,
APIViewTestCases.ListObjectsViewTestCase,
APIViewTestCases.CreateObjectViewTestCase,
APIViewTestCases.UpdateObjectViewTestCase,
APIViewTestCases.DeleteObjectViewTestCase
):
model = Token
brief_fields = ['description', 'display', 'id', 'key', 'url', 'write_enabled']
bulk_update_data = {
'description': 'New description',
}
def setUp(self):
super().setUp()
# Apply grant_token permission to enable the creation of Tokens for other Users
self.add_permissions('users.grant_token')
@classmethod
def setUpTestData(cls):
users = (
create_test_user('User1'),
create_test_user('User2'),
create_test_user('User3'),
)
tokens = (
Token(user=users[0]),
Token(user=users[1]),
Token(user=users[2]),
)
# Use save() instead of bulk_create() to ensure keys get automatically generated
for token in tokens:
token.save()
cls.create_data = [
{
'user': users[0].pk,
},
{
'user': users[1].pk,
},
{
'user': users[2].pk,
},
]
def test_provision_token_valid(self):
"""
Test the provisioning of a new REST API token given a valid username and password.
"""
user_credentials = {
'username': 'user1',
'password': 'abc123',
}
user = User.objects.create_user(**user_credentials)
data = {
**user_credentials,
'description': 'My API token',
'expires': '2099-12-31T23:59:59Z',
}
url = reverse('users-api:token_provision')
response = self.client.post(url, data, format='json', **self.header)
self.assertEqual(response.status_code, 201)
self.assertIn('key', response.data)
self.assertEqual(len(response.data['key']), 40)
self.assertEqual(response.data['description'], data['description'])
self.assertEqual(response.data['expires'], data['expires'])
token = Token.objects.get(user=user)
self.assertEqual(token.key, response.data['key'])
def test_provision_token_invalid(self):
"""
Test the behavior of the token provisioning view when invalid credentials are supplied.
"""
data = {
'username': 'nonexistentuser',
'password': 'abc123',
}
url = reverse('users-api:token_provision')
response = self.client.post(url, data, format='json', **self.header)
self.assertEqual(response.status_code, 403)
def test_provision_token_other_user(self):
"""
Test provisioning a Token for a different User with & without the grant_token permission.
"""
# Clear grant_token permission assigned by setUpTestData
ObjectPermission.objects.filter(users=self.user).delete()
self.add_permissions('users.add_token')
user2 = User.objects.create_user(username='testuser2')
data = {
'user': user2.id,
}
url = reverse('users-api:token-list')
# Attempt to create a new Token for User2 *without* the grant_token permission
response = self.client.post(url, data, format='json', **self.header)
self.assertEqual(response.status_code, 403)
# Assign grant_token permission and successfully create a new Token for User2
self.add_permissions('users.grant_token')
response = self.client.post(url, data, format='json', **self.header)
self.assertEqual(response.status_code, 201)
class ObjectPermissionTest(
# No GraphQL support for ObjectPermission
APIViewTestCases.GetObjectViewTestCase,
APIViewTestCases.ListObjectsViewTestCase,
APIViewTestCases.CreateObjectViewTestCase,
APIViewTestCases.UpdateObjectViewTestCase,
APIViewTestCases.DeleteObjectViewTestCase
):
model = ObjectPermission
brief_fields = ['actions', 'description', 'display', 'enabled', 'id', 'name', 'object_types', 'url']
@classmethod
def setUpTestData(cls):
groups = (
Group(name='Group 1'),
Group(name='Group 2'),
Group(name='Group 3'),
)
Group.objects.bulk_create(groups)
users = (
User(username='User1', is_active=True),
User(username='User2', is_active=True),
User(username='User3', is_active=True),
)
User.objects.bulk_create(users)
object_type = ObjectType.objects.get(app_label='dcim', model='device')
for i in range(3):
objectpermission = ObjectPermission(
name=f'Permission {i + 1}',
actions=['view', 'add', 'change', 'delete'],
constraints={'name': f'TEST{i + 1}'}
)
objectpermission.save()
objectpermission.object_types.add(object_type)
objectpermission.groups.add(groups[i])
objectpermission.users.add(users[i])
cls.create_data = [
{
'name': 'Permission 4',
'object_types': ['dcim.site'],
'groups': [groups[0].pk],
'users': [users[0].pk],
'actions': ['view', 'add', 'change', 'delete'],
'constraints': {'name': 'TEST4'},
},
{
'name': 'Permission 5',
'object_types': ['dcim.site'],
'groups': [groups[1].pk],
'users': [users[1].pk],
'actions': ['view', 'add', 'change', 'delete'],
'constraints': {'name': 'TEST5'},
},
{
'name': 'Permission 6',
'object_types': ['dcim.site'],
'groups': [groups[2].pk],
'users': [users[2].pk],
'actions': ['view', 'add', 'change', 'delete'],
'constraints': {'name': 'TEST6'},
},
]
cls.bulk_update_data = {
'description': 'New description',
}
class UserConfigTest(APITestCase):
def test_get(self):
"""
Retrieve user configuration via GET request.
"""
userconfig = self.user.config
url = reverse('users-api:userconfig-list')
response = self.client.get(url, **self.header)
self.assertEqual(response.data, {})
data = {
"a": 123,
"b": 456,
"c": 789,
}
userconfig.data = data
userconfig.save()
response = self.client.get(url, **self.header)
self.assertEqual(response.data, data)
def test_patch(self):
"""
Set user config via PATCH requests.
"""
userconfig = self.user.config
url = reverse('users-api:userconfig-list')
data = {
"a": {
"a1": "X",
"a2": "Y",
},
"b": {
"b1": "Z",
}
}
response = self.client.patch(url, data=data, format='json', **self.header)
self.assertDictEqual(response.data, data)
userconfig.refresh_from_db()
self.assertDictEqual(userconfig.data, data)
update_data = {
"c": 123
}
response = self.client.patch(url, data=update_data, format='json', **self.header)
new_data = deepmerge(data, update_data)
self.assertDictEqual(response.data, new_data)
userconfig.refresh_from_db()
self.assertDictEqual(userconfig.data, new_data)