Fix bulk creation of Secrets via API

This commit is contained in:
Jeremy Stretch 2018-01-02 17:07:21 -05:00
parent e5c13d2d72
commit 9c27d18d6c
3 changed files with 23 additions and 22 deletions

View File

@ -50,8 +50,15 @@ class WritableSecretSerializer(serializers.ModelSerializer):
def validate(self, data): def validate(self, data):
# Encrypt plaintext data using the master key provided from the view context
if data.get('plaintext'):
s = Secret(plaintext=data['plaintext'])
s.encrypt(self.context['master_key'])
data['ciphertext'] = s.ciphertext
data['hash'] = s.hash
# Validate uniqueness of name if one has been provided. # Validate uniqueness of name if one has been provided.
if data.get('name', None): if data.get('name'):
validator = UniqueTogetherValidator(queryset=Secret.objects.all(), fields=('device', 'role', 'name')) validator = UniqueTogetherValidator(queryset=Secret.objects.all(), fields=('device', 'role', 'name'))
validator.set_context(self) validator.set_context(self)
validator(data) validator(data)

View File

@ -56,17 +56,13 @@ class SecretViewSet(ModelViewSet):
master_key = None master_key = None
def _get_encrypted_fields(self, serializer): def get_serializer_context(self):
"""
Since we can't call encrypt() on the serializer like we can on the Secret model, we need to calculate the # Make the master key available to the serializer for encrypting plaintext values
ciphertext and hash values by encrypting a dummy copy. These can be passed to the serializer's save() method. context = super(SecretViewSet, self).get_serializer_context()
""" context['master_key'] = self.master_key
s = Secret(plaintext=serializer.validated_data['plaintext'])
s.encrypt(self.master_key) return context
return ({
'ciphertext': s.ciphertext,
'hash': s.hash,
})
def initial(self, request, *args, **kwargs): def initial(self, request, *args, **kwargs):
@ -128,12 +124,6 @@ class SecretViewSet(ModelViewSet):
serializer = self.get_serializer(queryset, many=True) serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data) return Response(serializer.data)
def perform_create(self, serializer):
serializer.save(**self._get_encrypted_fields(serializer))
def perform_update(self, serializer):
serializer.save(**self._get_encrypted_fields(serializer))
class GetSessionKeyViewSet(ViewSet): class GetSessionKeyViewSet(ViewSet):
""" """

View File

@ -164,9 +164,9 @@ class SecretTest(HttpStatusMixin, APITestCase):
} }
self.plaintext = { self.plaintext = {
'secret1': 'Secret#1Plaintext', 'secret1': 'Secret #1 Plaintext',
'secret2': 'Secret#2Plaintext', 'secret2': 'Secret #2 Plaintext',
'secret3': 'Secret#3Plaintext', 'secret3': 'Secret #3 Plaintext',
} }
site = Site.objects.create(name='Test Site 1', slug='test-site-1') site = Site.objects.create(name='Test Site 1', slug='test-site-1')
@ -213,7 +213,8 @@ class SecretTest(HttpStatusMixin, APITestCase):
data = { data = {
'device': self.device.pk, 'device': self.device.pk,
'role': self.secretrole1.pk, 'role': self.secretrole1.pk,
'plaintext': 'Secret#4Plaintext', 'name': 'Test Secret 4',
'plaintext': 'Secret #4 Plaintext',
} }
url = reverse('secrets-api:secret-list') url = reverse('secrets-api:secret-list')
@ -233,16 +234,19 @@ class SecretTest(HttpStatusMixin, APITestCase):
{ {
'device': self.device.pk, 'device': self.device.pk,
'role': self.secretrole1.pk, 'role': self.secretrole1.pk,
'name': 'Test Secret 4',
'plaintext': 'Secret #4 Plaintext', 'plaintext': 'Secret #4 Plaintext',
}, },
{ {
'device': self.device.pk, 'device': self.device.pk,
'role': self.secretrole1.pk, 'role': self.secretrole1.pk,
'name': 'Test Secret 5',
'plaintext': 'Secret #5 Plaintext', 'plaintext': 'Secret #5 Plaintext',
}, },
{ {
'device': self.device.pk, 'device': self.device.pk,
'role': self.secretrole1.pk, 'role': self.secretrole1.pk,
'name': 'Test Secret 6',
'plaintext': 'Secret #6 Plaintext', 'plaintext': 'Secret #6 Plaintext',
}, },
] ]