views.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. from django.contrib import messages
  2. from django.contrib.auth.decorators import permission_required, login_required
  3. from django.contrib.auth.mixins import PermissionRequiredMixin
  4. from django.core.urlresolvers import reverse
  5. from django.db import transaction, IntegrityError
  6. from django.db.models import Count
  7. from django.shortcuts import get_object_or_404, redirect, render
  8. from django.utils.decorators import method_decorator
  9. from dcim.models import Device
  10. from utilities.views import BulkDeleteView, BulkEditView, ObjectDeleteView, ObjectEditView, ObjectListView
  11. from . import filters, forms, tables
  12. from .decorators import userkey_required
  13. from .models import SecretRole, Secret, UserKey
  14. #
  15. # Secret roles
  16. #
  17. class SecretRoleListView(ObjectListView):
  18. queryset = SecretRole.objects.annotate(secret_count=Count('secrets'))
  19. table = tables.SecretRoleTable
  20. edit_permissions = ['secrets.change_secretrole', 'secrets.delete_secretrole']
  21. template_name = 'secrets/secretrole_list.html'
  22. class SecretRoleEditView(PermissionRequiredMixin, ObjectEditView):
  23. permission_required = 'secrets.change_secretrole'
  24. model = SecretRole
  25. form_class = forms.SecretRoleForm
  26. def get_return_url(self, obj):
  27. return reverse('secrets:secretrole_list')
  28. class SecretRoleBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  29. permission_required = 'secrets.delete_secretrole'
  30. cls = SecretRole
  31. default_return_url = 'secrets:secretrole_list'
  32. #
  33. # Secrets
  34. #
  35. @method_decorator(login_required, name='dispatch')
  36. class SecretListView(ObjectListView):
  37. queryset = Secret.objects.select_related('role').prefetch_related('device')
  38. filter = filters.SecretFilter
  39. filter_form = forms.SecretFilterForm
  40. table = tables.SecretTable
  41. edit_permissions = ['secrets.change_secret', 'secrets.delete_secret']
  42. template_name = 'secrets/secret_list.html'
  43. @login_required
  44. def secret(request, pk):
  45. secret = get_object_or_404(Secret, pk=pk)
  46. return render(request, 'secrets/secret.html', {
  47. 'secret': secret,
  48. })
  49. @permission_required('secrets.add_secret')
  50. @userkey_required()
  51. def secret_add(request, pk):
  52. # Retrieve device
  53. device = get_object_or_404(Device, pk=pk)
  54. secret = Secret(device=device)
  55. uk = UserKey.objects.get(user=request.user)
  56. if request.method == 'POST':
  57. form = forms.SecretForm(request.POST, instance=secret)
  58. if form.is_valid():
  59. # Retrieve the master key from the current user's UserKey
  60. master_key = uk.get_master_key(form.cleaned_data['private_key'])
  61. if master_key is None:
  62. form.add_error(None, "Invalid private key! Unable to encrypt secret data.")
  63. # Create and encrypt the new Secret
  64. else:
  65. secret = form.save(commit=False)
  66. secret.plaintext = str(form.cleaned_data['plaintext'])
  67. secret.encrypt(master_key)
  68. secret.save()
  69. messages.success(request, u"Added new secret: {}.".format(secret))
  70. if '_addanother' in request.POST:
  71. return redirect('dcim:device_addsecret', pk=device.pk)
  72. else:
  73. return redirect('secrets:secret', pk=secret.pk)
  74. else:
  75. form = forms.SecretForm(instance=secret)
  76. return render(request, 'secrets/secret_edit.html', {
  77. 'secret': secret,
  78. 'form': form,
  79. 'return_url': device.get_absolute_url(),
  80. })
  81. @permission_required('secrets.change_secret')
  82. @userkey_required()
  83. def secret_edit(request, pk):
  84. secret = get_object_or_404(Secret, pk=pk)
  85. uk = UserKey.objects.get(user=request.user)
  86. if request.method == 'POST':
  87. form = forms.SecretForm(request.POST, instance=secret)
  88. if form.is_valid():
  89. # Re-encrypt the Secret if a plaintext has been specified.
  90. if form.cleaned_data['plaintext']:
  91. # Retrieve the master key from the current user's UserKey
  92. master_key = uk.get_master_key(form.cleaned_data['private_key'])
  93. if master_key is None:
  94. form.add_error(None, "Invalid private key! Unable to encrypt secret data.")
  95. # Create and encrypt the new Secret
  96. else:
  97. secret = form.save(commit=False)
  98. secret.plaintext = str(form.cleaned_data['plaintext'])
  99. secret.encrypt(master_key)
  100. secret.save()
  101. else:
  102. secret = form.save()
  103. messages.success(request, u"Modified secret {}.".format(secret))
  104. return redirect('secrets:secret', pk=secret.pk)
  105. else:
  106. form = forms.SecretForm(instance=secret)
  107. return render(request, 'secrets/secret_edit.html', {
  108. 'secret': secret,
  109. 'form': form,
  110. 'return_url': reverse('secrets:secret', kwargs={'pk': secret.pk}),
  111. })
  112. class SecretDeleteView(PermissionRequiredMixin, ObjectDeleteView):
  113. permission_required = 'secrets.delete_secret'
  114. model = Secret
  115. default_return_url = 'secrets:secret_list'
  116. @permission_required('secrets.add_secret')
  117. @userkey_required()
  118. def secret_import(request):
  119. uk = UserKey.objects.get(user=request.user)
  120. if request.method == 'POST':
  121. form = forms.SecretImportForm(request.POST)
  122. if form.is_valid():
  123. new_secrets = []
  124. # Retrieve the master key from the current user's UserKey
  125. master_key = uk.get_master_key(form.cleaned_data['private_key'])
  126. if master_key is None:
  127. form.add_error(None, "Invalid private key! Unable to encrypt secret data.")
  128. else:
  129. try:
  130. with transaction.atomic():
  131. for secret in form.cleaned_data['csv']:
  132. secret.encrypt(master_key)
  133. secret.save()
  134. new_secrets.append(secret)
  135. table = tables.SecretTable(new_secrets)
  136. messages.success(request, u"Imported {} new secrets.".format(len(new_secrets)))
  137. return render(request, 'import_success.html', {
  138. 'table': table,
  139. })
  140. except IntegrityError as e:
  141. form.add_error('csv', "Record {}: {}".format(len(new_secrets) + 1, e.__cause__))
  142. else:
  143. form = forms.SecretImportForm()
  144. return render(request, 'secrets/secret_import.html', {
  145. 'form': form,
  146. 'return_url': reverse('secrets:secret_list'),
  147. })
  148. class SecretBulkEditView(PermissionRequiredMixin, BulkEditView):
  149. permission_required = 'secrets.change_secret'
  150. cls = Secret
  151. filter = filters.SecretFilter
  152. form = forms.SecretBulkEditForm
  153. template_name = 'secrets/secret_bulk_edit.html'
  154. default_return_url = 'secrets:secret_list'
  155. class SecretBulkDeleteView(PermissionRequiredMixin, BulkDeleteView):
  156. permission_required = 'secrets.delete_secret'
  157. cls = Secret
  158. filter = filters.SecretFilter
  159. default_return_url = 'secrets:secret_list'