Closes #1739: Enabled custom fields for secrets

This commit is contained in:
Jeremy Stretch 2018-07-17 09:43:57 -04:00
parent 9e2ac7b3f4
commit 0c0799f3bf
7 changed files with 32 additions and 10 deletions

View File

@ -6,6 +6,7 @@ CUSTOMFIELD_MODELS = (
'provider', 'circuit', # Circuits
'site', 'rack', 'devicetype', 'device', # DCIM
'aggregate', 'prefix', 'ipaddress', 'vlan', 'vrf', 'service', # IPAM
'secret', # Secrets
'tenant', # Tenancy
'cluster', 'virtualmachine', # Virtualization
)

View File

@ -5,6 +5,7 @@ from rest_framework.validators import UniqueTogetherValidator
from taggit.models import Tag
from dcim.api.serializers import NestedDeviceSerializer
from extras.api.customfields import CustomFieldModelSerializer
from secrets.models import Secret, SecretRole
from utilities.api import TagField, ValidatedModelSerializer, WritableNestedSerializer
@ -32,7 +33,7 @@ class NestedSecretRoleSerializer(WritableNestedSerializer):
# Secrets
#
class SecretSerializer(ValidatedModelSerializer):
class SecretSerializer(CustomFieldModelSerializer):
device = NestedDeviceSerializer()
role = NestedSecretRoleSerializer()
plaintext = serializers.CharField()
@ -40,7 +41,9 @@ class SecretSerializer(ValidatedModelSerializer):
class Meta:
model = Secret
fields = ['id', 'device', 'role', 'name', 'plaintext', 'hash', 'tags', 'created', 'last_updated']
fields = [
'id', 'device', 'role', 'name', 'plaintext', 'hash', 'tags', 'custom_fields', 'created', 'last_updated',
]
validators = []
def validate(self, data):

View File

@ -4,6 +4,7 @@ import django_filters
from django.db.models import Q
from dcim.models import Device
from extras.filters import CustomFieldFilterSet
from utilities.filters import NumericInFilter
from .models import Secret, SecretRole
@ -15,7 +16,7 @@ class SecretRoleFilter(django_filters.FilterSet):
fields = ['name', 'slug']
class SecretFilter(django_filters.FilterSet):
class SecretFilter(CustomFieldFilterSet, django_filters.FilterSet):
id__in = NumericInFilter(name='id', lookup_expr='in')
q = django_filters.CharFilter(
method='search',

View File

@ -7,8 +7,8 @@ from django.db.models import Count
from taggit.forms import TagField
from dcim.models import Device
from extras.forms import AddRemoveTagsForm
from utilities.forms import BootstrapMixin, BulkEditForm, FilterChoiceField, FlexibleModelChoiceField, SlugField
from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldFilterForm, CustomFieldForm
from utilities.forms import BootstrapMixin, FilterChoiceField, FlexibleModelChoiceField, SlugField
from .models import Secret, SecretRole, UserKey
@ -59,7 +59,7 @@ class SecretRoleCSVForm(forms.ModelForm):
# Secrets
#
class SecretForm(BootstrapMixin, forms.ModelForm):
class SecretForm(BootstrapMixin, CustomFieldForm):
plaintext = forms.CharField(
max_length=65535,
required=False,
@ -129,7 +129,7 @@ class SecretCSVForm(forms.ModelForm):
return s
class SecretBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
class SecretBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEditForm):
pk = forms.ModelMultipleChoiceField(queryset=Secret.objects.all(), widget=forms.MultipleHiddenInput)
role = forms.ModelChoiceField(queryset=SecretRole.objects.all(), required=False)
name = forms.CharField(max_length=100, required=False)
@ -138,7 +138,8 @@ class SecretBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
nullable_fields = ['name']
class SecretFilterForm(BootstrapMixin, forms.Form):
class SecretFilterForm(BootstrapMixin, CustomFieldFilterForm):
model = Secret
q = forms.CharField(required=False, label='Search')
role = FilterChoiceField(
queryset=SecretRole.objects.annotate(filter_count=Count('secrets')),

View File

@ -8,12 +8,14 @@ from Crypto.Util import strxor
from django.conf import settings
from django.contrib.auth.hashers import make_password, check_password
from django.contrib.auth.models import Group, User
from django.contrib.contenttypes.fields import GenericRelation
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from django.utils.encoding import force_bytes, python_2_unicode_compatible
from taggit.managers import TaggableManager
from extras.models import CustomFieldModel
from utilities.models import ChangeLoggedModel
from .exceptions import InvalidKey
from .hashers import SecretValidationHasher
@ -311,7 +313,7 @@ class SecretRole(ChangeLoggedModel):
@python_2_unicode_compatible
class Secret(ChangeLoggedModel):
class Secret(ChangeLoggedModel, CustomFieldModel):
"""
A Secret stores an AES256-encrypted copy of sensitive data, such as passwords or secret keys. An irreversible
SHA-256 hash is stored along with the ciphertext for validation upon decryption. Each Secret is assigned to a
@ -343,6 +345,11 @@ class Secret(ChangeLoggedModel):
max_length=128,
editable=False
)
custom_field_values = GenericRelation(
to='extras.CustomFieldValue',
content_type_field='obj_type',
object_id_field='obj_id'
)
tags = TaggableManager()

View File

@ -69,7 +69,7 @@
</tr>
</table>
</div>
{% include 'extras/inc/tags_panel.html' with tags=secret.tags.all url='secrets:secret_list' %}
{% include 'inc/custom_fields_panel.html' with custom_fields=secret.get_custom_fields %}
</div>
<div class="col-md-6">
{% if secret|decryptable_by:request.user %}
@ -101,6 +101,7 @@
You do not have permission to decrypt this secret.
</div>
{% endif %}
{% include 'extras/inc/tags_panel.html' with tags=secret.tags.all url='secrets:secret_list' %}
</div>
</div>

View File

@ -54,6 +54,14 @@
{% render_field form.plaintext2 %}
</div>
</div>
{% if form.custom_fields %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Custom Fields</strong></div>
<div class="panel-body">
{% render_custom_fields form %}
</div>
</div>
{% endif %}
<div class="panel panel-default">
<div class="panel-heading"><strong>Tags</strong></div>
<div class="panel-body">