mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
385 lines
12 KiB
Python
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)
|