test_api.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331
  1. import base64
  2. from django.urls import reverse
  3. from rest_framework import status
  4. from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
  5. from secrets.models import Secret, SecretRole, SessionKey, UserKey
  6. from users.models import Token
  7. from utilities.testing import APITestCase, create_test_user
  8. from .constants import PRIVATE_KEY, PUBLIC_KEY
  9. class AppTest(APITestCase):
  10. def test_root(self):
  11. url = reverse('secrets-api:api-root')
  12. response = self.client.get('{}?format=api'.format(url), **self.header)
  13. self.assertEqual(response.status_code, 200)
  14. class SecretRoleTest(APITestCase):
  15. def setUp(self):
  16. super().setUp()
  17. self.secretrole1 = SecretRole.objects.create(name='Test Secret Role 1', slug='test-secret-role-1')
  18. self.secretrole2 = SecretRole.objects.create(name='Test Secret Role 2', slug='test-secret-role-2')
  19. self.secretrole3 = SecretRole.objects.create(name='Test Secret Role 3', slug='test-secret-role-3')
  20. def test_get_secretrole(self):
  21. url = reverse('secrets-api:secretrole-detail', kwargs={'pk': self.secretrole1.pk})
  22. response = self.client.get(url, **self.header)
  23. self.assertEqual(response.data['name'], self.secretrole1.name)
  24. def test_list_secretroles(self):
  25. url = reverse('secrets-api:secretrole-list')
  26. response = self.client.get(url, **self.header)
  27. self.assertEqual(response.data['count'], 3)
  28. def test_list_secretroles_brief(self):
  29. url = reverse('secrets-api:secretrole-list')
  30. response = self.client.get('{}?brief=1'.format(url), **self.header)
  31. self.assertEqual(
  32. sorted(response.data['results'][0]),
  33. ['id', 'name', 'secret_count', 'slug', 'url']
  34. )
  35. def test_create_secretrole(self):
  36. data = {
  37. 'name': 'Test Secret Role 4',
  38. 'slug': 'test-secret-role-4',
  39. }
  40. url = reverse('secrets-api:secretrole-list')
  41. response = self.client.post(url, data, format='json', **self.header)
  42. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  43. self.assertEqual(SecretRole.objects.count(), 4)
  44. secretrole4 = SecretRole.objects.get(pk=response.data['id'])
  45. self.assertEqual(secretrole4.name, data['name'])
  46. self.assertEqual(secretrole4.slug, data['slug'])
  47. def test_create_secretrole_bulk(self):
  48. data = [
  49. {
  50. 'name': 'Test Secret Role 4',
  51. 'slug': 'test-secret-role-4',
  52. },
  53. {
  54. 'name': 'Test Secret Role 5',
  55. 'slug': 'test-secret-role-5',
  56. },
  57. {
  58. 'name': 'Test Secret Role 6',
  59. 'slug': 'test-secret-role-6',
  60. },
  61. ]
  62. url = reverse('secrets-api:secretrole-list')
  63. response = self.client.post(url, data, format='json', **self.header)
  64. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  65. self.assertEqual(SecretRole.objects.count(), 6)
  66. self.assertEqual(response.data[0]['name'], data[0]['name'])
  67. self.assertEqual(response.data[1]['name'], data[1]['name'])
  68. self.assertEqual(response.data[2]['name'], data[2]['name'])
  69. def test_update_secretrole(self):
  70. data = {
  71. 'name': 'Test SecretRole X',
  72. 'slug': 'test-secretrole-x',
  73. }
  74. url = reverse('secrets-api:secretrole-detail', kwargs={'pk': self.secretrole1.pk})
  75. response = self.client.put(url, data, format='json', **self.header)
  76. self.assertHttpStatus(response, status.HTTP_200_OK)
  77. self.assertEqual(SecretRole.objects.count(), 3)
  78. secretrole1 = SecretRole.objects.get(pk=response.data['id'])
  79. self.assertEqual(secretrole1.name, data['name'])
  80. self.assertEqual(secretrole1.slug, data['slug'])
  81. def test_delete_secretrole(self):
  82. url = reverse('secrets-api:secretrole-detail', kwargs={'pk': self.secretrole1.pk})
  83. response = self.client.delete(url, **self.header)
  84. self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
  85. self.assertEqual(SecretRole.objects.count(), 2)
  86. class SecretTest(APITestCase):
  87. def setUp(self):
  88. # Create a non-superuser test user
  89. self.user = create_test_user('testuser', permissions=(
  90. 'secrets.add_secret',
  91. 'secrets.change_secret',
  92. 'secrets.delete_secret',
  93. 'secrets.view_secret',
  94. ))
  95. self.token = Token.objects.create(user=self.user)
  96. self.header = {'HTTP_AUTHORIZATION': 'Token {}'.format(self.token.key)}
  97. userkey = UserKey(user=self.user, public_key=PUBLIC_KEY)
  98. userkey.save()
  99. self.master_key = userkey.get_master_key(PRIVATE_KEY)
  100. session_key = SessionKey(userkey=userkey)
  101. session_key.save(self.master_key)
  102. self.header = {
  103. 'HTTP_AUTHORIZATION': 'Token {}'.format(self.token.key),
  104. 'HTTP_X_SESSION_KEY': base64.b64encode(session_key.key),
  105. }
  106. self.plaintexts = (
  107. 'Secret #1 Plaintext',
  108. 'Secret #2 Plaintext',
  109. 'Secret #3 Plaintext',
  110. )
  111. site = Site.objects.create(name='Test Site 1', slug='test-site-1')
  112. manufacturer = Manufacturer.objects.create(name='Test Manufacturer 1', slug='test-manufacturer-1')
  113. devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Test Device Type 1')
  114. devicerole = DeviceRole.objects.create(name='Test Device Role 1', slug='test-device-role-1')
  115. self.device = Device.objects.create(
  116. name='Test Device 1', site=site, device_type=devicetype, device_role=devicerole
  117. )
  118. self.secretrole1 = SecretRole.objects.create(name='Test Secret Role 1', slug='test-secret-role-1')
  119. self.secretrole2 = SecretRole.objects.create(name='Test Secret Role 2', slug='test-secret-role-2')
  120. self.secret1 = Secret(
  121. device=self.device, role=self.secretrole1, name='Test Secret 1', plaintext=self.plaintexts[0]
  122. )
  123. self.secret1.encrypt(self.master_key)
  124. self.secret1.save()
  125. self.secret2 = Secret(
  126. device=self.device, role=self.secretrole1, name='Test Secret 2', plaintext=self.plaintexts[1]
  127. )
  128. self.secret2.encrypt(self.master_key)
  129. self.secret2.save()
  130. self.secret3 = Secret(
  131. device=self.device, role=self.secretrole1, name='Test Secret 3', plaintext=self.plaintexts[2]
  132. )
  133. self.secret3.encrypt(self.master_key)
  134. self.secret3.save()
  135. def test_get_secret(self):
  136. url = reverse('secrets-api:secret-detail', kwargs={'pk': self.secret1.pk})
  137. # Secret plaintext not be decrypted as the user has not been assigned to the role
  138. response = self.client.get(url, **self.header)
  139. self.assertIsNone(response.data['plaintext'])
  140. # The plaintext should be present once the user has been assigned to the role
  141. self.secretrole1.users.add(self.user)
  142. response = self.client.get(url, **self.header)
  143. self.assertEqual(response.data['plaintext'], self.plaintexts[0])
  144. def test_list_secrets(self):
  145. url = reverse('secrets-api:secret-list')
  146. # Secret plaintext not be decrypted as the user has not been assigned to the role
  147. response = self.client.get(url, **self.header)
  148. self.assertEqual(response.data['count'], 3)
  149. for secret in response.data['results']:
  150. self.assertIsNone(secret['plaintext'])
  151. # The plaintext should be present once the user has been assigned to the role
  152. self.secretrole1.users.add(self.user)
  153. response = self.client.get(url, **self.header)
  154. self.assertEqual(response.data['count'], 3)
  155. for i, secret in enumerate(response.data['results']):
  156. self.assertEqual(secret['plaintext'], self.plaintexts[i])
  157. def test_create_secret(self):
  158. data = {
  159. 'device': self.device.pk,
  160. 'role': self.secretrole1.pk,
  161. 'name': 'Test Secret 4',
  162. 'plaintext': 'Secret #4 Plaintext',
  163. }
  164. url = reverse('secrets-api:secret-list')
  165. response = self.client.post(url, data, format='json', **self.header)
  166. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  167. self.assertEqual(response.data['plaintext'], data['plaintext'])
  168. self.assertEqual(Secret.objects.count(), 4)
  169. secret4 = Secret.objects.get(pk=response.data['id'])
  170. secret4.decrypt(self.master_key)
  171. self.assertEqual(secret4.role_id, data['role'])
  172. self.assertEqual(secret4.plaintext, data['plaintext'])
  173. def test_create_secret_bulk(self):
  174. data = [
  175. {
  176. 'device': self.device.pk,
  177. 'role': self.secretrole1.pk,
  178. 'name': 'Test Secret 4',
  179. 'plaintext': 'Secret #4 Plaintext',
  180. },
  181. {
  182. 'device': self.device.pk,
  183. 'role': self.secretrole1.pk,
  184. 'name': 'Test Secret 5',
  185. 'plaintext': 'Secret #5 Plaintext',
  186. },
  187. {
  188. 'device': self.device.pk,
  189. 'role': self.secretrole1.pk,
  190. 'name': 'Test Secret 6',
  191. 'plaintext': 'Secret #6 Plaintext',
  192. },
  193. ]
  194. url = reverse('secrets-api:secret-list')
  195. response = self.client.post(url, data, format='json', **self.header)
  196. self.assertHttpStatus(response, status.HTTP_201_CREATED)
  197. self.assertEqual(Secret.objects.count(), 6)
  198. self.assertEqual(response.data[0]['plaintext'], data[0]['plaintext'])
  199. self.assertEqual(response.data[1]['plaintext'], data[1]['plaintext'])
  200. self.assertEqual(response.data[2]['plaintext'], data[2]['plaintext'])
  201. def test_update_secret(self):
  202. data = {
  203. 'device': self.device.pk,
  204. 'role': self.secretrole2.pk,
  205. 'plaintext': 'NewPlaintext',
  206. }
  207. url = reverse('secrets-api:secret-detail', kwargs={'pk': self.secret1.pk})
  208. response = self.client.put(url, data, format='json', **self.header)
  209. self.assertHttpStatus(response, status.HTTP_200_OK)
  210. self.assertEqual(response.data['plaintext'], data['plaintext'])
  211. self.assertEqual(Secret.objects.count(), 3)
  212. secret1 = Secret.objects.get(pk=response.data['id'])
  213. secret1.decrypt(self.master_key)
  214. self.assertEqual(secret1.role_id, data['role'])
  215. self.assertEqual(secret1.plaintext, data['plaintext'])
  216. def test_delete_secret(self):
  217. url = reverse('secrets-api:secret-detail', kwargs={'pk': self.secret1.pk})
  218. response = self.client.delete(url, **self.header)
  219. self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
  220. self.assertEqual(Secret.objects.count(), 2)
  221. class GetSessionKeyTest(APITestCase):
  222. def setUp(self):
  223. super().setUp()
  224. userkey = UserKey(user=self.user, public_key=PUBLIC_KEY)
  225. userkey.save()
  226. master_key = userkey.get_master_key(PRIVATE_KEY)
  227. self.session_key = SessionKey(userkey=userkey)
  228. self.session_key.save(master_key)
  229. self.header = {
  230. 'HTTP_AUTHORIZATION': 'Token {}'.format(self.token.key),
  231. }
  232. def test_get_session_key(self):
  233. encoded_session_key = base64.b64encode(self.session_key.key).decode()
  234. url = reverse('secrets-api:get-session-key-list')
  235. data = {
  236. 'private_key': PRIVATE_KEY,
  237. }
  238. response = self.client.post(url, data, **self.header)
  239. self.assertHttpStatus(response, status.HTTP_200_OK)
  240. self.assertIsNotNone(response.data.get('session_key'))
  241. self.assertNotEqual(response.data.get('session_key'), encoded_session_key)
  242. def test_get_session_key_preserved(self):
  243. encoded_session_key = base64.b64encode(self.session_key.key).decode()
  244. url = reverse('secrets-api:get-session-key-list') + '?preserve_key=True'
  245. data = {
  246. 'private_key': PRIVATE_KEY,
  247. }
  248. response = self.client.post(url, data, **self.header)
  249. self.assertHttpStatus(response, status.HTTP_200_OK)
  250. self.assertEqual(response.data.get('session_key'), encoded_session_key)