Skip to content

Commit 724c6e0

Browse files
authored
Merge pull request #678 from DefectDojo/dev
Dev
2 parents 24f1fa6 + 4a4e520 commit 724c6e0

35 files changed

+947
-237
lines changed

docker/docker-startup.bash

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ else
9797
echo
9898
#Start gunicorn
9999
cd $DOJO_ROOT_DIR
100-
gunicorn --env DJANGO_SETTINGS_MODULE=dojo.settings dojo.wsgi:application --bind 0.0.0.0:$PORT --workers 3 & celery -A dojo worker -l info --concurrency 3
100+
gunicorn --env DJANGO_SETTINGS_MODULE=dojo.settings.settings dojo.wsgi:application --bind 0.0.0.0:$PORT --workers 3 & celery -A dojo worker -l info --concurrency 3
101101
else
102102
echo "MySQL server is down or dojo can't access mysql"
103103
echo "Exiting startup script..."

dojo/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Django starts so that shared_task will use this app.
55
from .celery import app as celery_app # noqa
66

7-
__version__ = '1.5.1'
7+
__version__ = '1.5.2'
88
__url__ = 'https://github.com/DefectDojo/django-DefectDojo'
99
__docs__ = 'http://defectdojo.readthedocs.io/'
1010
__demo__ = 'http://defectdojo.pythonanywhere.com/'

dojo/api.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -476,11 +476,11 @@ class EngagementResource(BaseModelResource):
476476
lead = fields.ForeignKey(UserResource, 'lead',
477477
full=False, null=True)
478478
source_code_management_server = fields.ForeignKey(Tool_ConfigurationResource, 'source_code_management_server',
479-
full=False, null=False)
479+
full=False, null=True)
480480
build_server = fields.ForeignKey(Tool_ConfigurationResource, 'build_server',
481-
full=False, null=False)
481+
full=False, null=True)
482482
orchestration_engine = fields.ForeignKey(Tool_ConfigurationResource, 'orchestration_engine',
483-
full=False, null=False)
483+
full=False, null=True)
484484

485485
class Meta:
486486
resource_name = 'engagements'
@@ -503,7 +503,6 @@ class Meta:
503503
'pen_test': ALL,
504504
'status': ALL,
505505
'product': ALL,
506-
'tool_configuration': ALL_WITH_RELATIONS,
507506
}
508507
authentication = DojoApiKeyAuthentication()
509508
authorization = DjangoAuthorization()

dojo/api_v2/serializers.py

Lines changed: 151 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,131 @@
33
Finding_Template, Test_Type, Development_Environment, Report_Type, \
44
JIRA_Issue, Tool_Product_Settings, Tool_Configuration, Tool_Type, \
55
Product_Type, JIRA_Conf, Endpoint, BurpRawRequestResponse, JIRA_PKey, \
6-
Notes, Dojo_User
6+
Notes, Dojo_User, Regulation
77
from dojo.forms import ImportScanForm, SEVERITY_CHOICES
88
from dojo.tools.factory import import_parser_factory
99
from django.core.validators import URLValidator, validate_ipv46_address
10-
1110
from rest_framework import serializers
1211
from django.core.exceptions import ValidationError
1312
from django.utils import timezone
1413
import datetime
14+
import six
15+
from django.utils.translation import ugettext_lazy as _
16+
import json
17+
18+
19+
class TagList(list):
20+
def __init__(self, *args, **kwargs):
21+
pretty_print = kwargs.pop("pretty_print", True)
22+
list.__init__(self, *args, **kwargs)
23+
self.pretty_print = pretty_print
24+
25+
def __add__(self, rhs):
26+
return TagList(list.__add__(self, rhs))
27+
28+
def __getitem__(self, item):
29+
result = list.__getitem__(self, item)
30+
try:
31+
return TagList(result)
32+
except TypeError:
33+
return result
34+
35+
def __str__(self):
36+
if self.pretty_print:
37+
return json.dumps(
38+
self, sort_keys=True, indent=4, separators=(',', ': '))
39+
else:
40+
return json.dumps(self)
41+
42+
43+
class TagListSerializerField(serializers.ListField):
44+
child = serializers.CharField()
45+
default_error_messages = {
46+
'not_a_list': _(
47+
'Expected a list of items but got type "{input_type}".'),
48+
'invalid_json': _('Invalid json list. A tag list submitted in string'
49+
' form must be valid json.'),
50+
'not_a_str': _('All list items must be of string type.')
51+
}
52+
order_by = None
53+
54+
def __init__(self, **kwargs):
55+
pretty_print = kwargs.pop("pretty_print", True)
56+
57+
style = kwargs.pop("style", {})
58+
kwargs["style"] = {'base_template': 'textarea.html'}
59+
kwargs["style"].update(style)
60+
61+
super(TagListSerializerField, self).__init__(**kwargs)
62+
63+
self.pretty_print = pretty_print
64+
65+
def to_internal_value(self, value):
66+
if isinstance(value, six.string_types):
67+
if not value:
68+
value = "[]"
69+
try:
70+
value = json.loads(value)
71+
except ValueError:
72+
self.fail('invalid_json')
73+
74+
if not isinstance(value, list):
75+
self.fail('not_a_list', input_type=type(value).__name__)
76+
77+
for s in value:
78+
if not isinstance(s, six.string_types):
79+
self.fail('not_a_str')
80+
81+
self.child.run_validation(s)
82+
83+
return value
84+
85+
def to_representation(self, value):
86+
if not isinstance(value, TagList):
87+
if not isinstance(value, list):
88+
if self.order_by:
89+
tags = value.all().order_by(*self.order_by)
90+
else:
91+
tags = value.all()
92+
value = [tag.name for tag in tags]
93+
value = TagList(value, pretty_print=self.pretty_print)
94+
95+
return value
96+
97+
98+
class TaggitSerializer(serializers.Serializer):
99+
def create(self, validated_data):
100+
to_be_tagged, validated_data = self._pop_tags(validated_data)
101+
102+
tag_object = super(TaggitSerializer, self).create(validated_data)
103+
104+
return self._save_tags(tag_object, to_be_tagged)
105+
106+
def update(self, instance, validated_data):
107+
to_be_tagged, validated_data = self._pop_tags(validated_data)
108+
109+
tag_object = super(TaggitSerializer, self).update(
110+
instance, validated_data)
111+
112+
return self._save_tags(tag_object, to_be_tagged)
113+
114+
def _save_tags(self, tag_object, tags):
115+
for key in tags.keys():
116+
tag_values = tags.get(key)
117+
tag_object.tags = ", ".join(tag_values)
118+
119+
return tag_object
120+
121+
def _pop_tags(self, validated_data):
122+
to_be_tagged = {}
123+
124+
for key in self.fields.keys():
125+
field = self.fields[key]
126+
if isinstance(field, TagListSerializerField):
127+
if key in validated_data:
128+
to_be_tagged[key] = validated_data.pop(key)
129+
130+
return (to_be_tagged, validated_data)
15131

16132

17133
class UserSerializer(serializers.HyperlinkedModelSerializer):
@@ -20,27 +136,30 @@ class Meta:
20136
fields = ('url', 'username', 'first_name', 'last_name', 'last_login')
21137

22138

23-
class ProductSerializer(serializers.HyperlinkedModelSerializer):
139+
class ProductSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
24140
findings_count = serializers.SerializerMethodField()
25141
product_manager = serializers.HyperlinkedRelatedField(
26142
queryset=User.objects.all(),
27143
view_name='user-detail',
28-
format='html')
144+
format='html', required=False)
29145
technical_contact = serializers.HyperlinkedRelatedField(
30146
queryset=User.objects.all(),
31147
view_name='user-detail',
32-
format='html')
148+
format='html', required=False)
33149
team_manager = serializers.HyperlinkedRelatedField(
34150
queryset=User.objects.all(),
35151
view_name='user-detail',
36-
format='html')
152+
format='html', required=False)
37153
authorized_users = serializers.HyperlinkedRelatedField(
38154
many=True,
39155
queryset=User.objects.exclude(is_staff=True).exclude(is_active=False),
40156
view_name='user-detail',
41-
format='html')
157+
format='html', required=False)
42158
prod_type = serializers.PrimaryKeyRelatedField(
43159
queryset=Product_Type.objects.all())
160+
regulations = serializers.PrimaryKeyRelatedField(
161+
queryset=Regulation.objects.all(), many=True, required=False)
162+
tags = TagListSerializerField(required=False)
44163

45164
class Meta:
46165
model = Product
@@ -51,11 +170,12 @@ def get_findings_count(self, obj):
51170
return obj.findings_count
52171

53172

54-
class EngagementSerializer(serializers.HyperlinkedModelSerializer):
173+
class EngagementSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
55174
eng_type = serializers.PrimaryKeyRelatedField(
56-
queryset=Engagement_Type.objects.all())
175+
queryset=Engagement_Type.objects.all(), required=False)
57176
report_type = serializers.PrimaryKeyRelatedField(
58-
queryset=Report_Type.objects.all())
177+
queryset=Report_Type.objects.all(), required=False)
178+
tags = TagListSerializerField(required=False)
59179

60180
class Meta:
61181
model = Engagement
@@ -95,7 +215,8 @@ class Meta:
95215
fields = '__all__'
96216

97217

98-
class EndpointSerializer(serializers.HyperlinkedModelSerializer):
218+
class EndpointSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
219+
tags = TagListSerializerField(required=False)
99220

100221
class Meta:
101222
model = Endpoint
@@ -204,7 +325,7 @@ class Meta:
204325
fields = '__all__'
205326

206327

207-
class TestSerializer(serializers.HyperlinkedModelSerializer):
328+
class TestSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
208329
engagement = serializers.HyperlinkedRelatedField(
209330
read_only=True,
210331
view_name='engagement-detail',
@@ -213,13 +334,17 @@ class TestSerializer(serializers.HyperlinkedModelSerializer):
213334
queryset=Test_Type.objects.all())
214335
environment = serializers.PrimaryKeyRelatedField(
215336
queryset=Development_Environment.objects.all())
337+
notes = serializers.PrimaryKeyRelatedField(
338+
queryset=Notes.objects.all(),
339+
many=True)
340+
tags = TagListSerializerField(required=False)
216341

217342
class Meta:
218343
model = Test
219344
fields = '__all__'
220345

221346

222-
class TestCreateSerializer(serializers.HyperlinkedModelSerializer):
347+
class TestCreateSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
223348
test_type = serializers.PrimaryKeyRelatedField(
224349
queryset=Test_Type.objects.all())
225350
environment = serializers.PrimaryKeyRelatedField(
@@ -233,6 +358,7 @@ class TestCreateSerializer(serializers.HyperlinkedModelSerializer):
233358
notes = serializers.PrimaryKeyRelatedField(
234359
queryset=Notes.objects.all(),
235360
many=True)
361+
tags = TagListSerializerField(required=False)
236362

237363
class Meta:
238364
model = Test
@@ -245,7 +371,7 @@ class Meta:
245371
fields = '__all__'
246372

247373

248-
class FindingSerializer(serializers.HyperlinkedModelSerializer):
374+
class FindingSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
249375
review_requested_by = serializers.HyperlinkedRelatedField(
250376
queryset=Dojo_User.objects.all(),
251377
view_name='user-detail',
@@ -274,6 +400,7 @@ class FindingSerializer(serializers.HyperlinkedModelSerializer):
274400
source='url',
275401
read_only=True)
276402
url = serializers.HyperlinkedIdentityField(view_name='finding-detail')
403+
tags = TagListSerializerField(required=False)
277404

278405
class Meta:
279406
model = Finding
@@ -299,7 +426,7 @@ def validate(self, data):
299426
return data
300427

301428

302-
class FindingCreateSerializer(serializers.HyperlinkedModelSerializer):
429+
class FindingCreateSerializer(TaggitSerializer, serializers.HyperlinkedModelSerializer):
303430
review_requested_by = serializers.HyperlinkedRelatedField(
304431
queryset=Dojo_User.objects.all(),
305432
view_name='user-detail',
@@ -330,6 +457,7 @@ class FindingCreateSerializer(serializers.HyperlinkedModelSerializer):
330457
queryset=Test_Type.objects.all(),
331458
many=True)
332459
url = serializers.CharField()
460+
tags = TagListSerializerField(required=False)
333461

334462
class Meta:
335463
model = Finding
@@ -418,7 +546,7 @@ class Meta:
418546
fields = '__all__'
419547

420548

421-
class ImportScanSerializer(serializers.Serializer):
549+
class ImportScanSerializer(TaggitSerializer, serializers.Serializer):
422550
scan_date = serializers.DateField()
423551
minimum_severity = serializers.ChoiceField(
424552
choices=SEVERITY_CHOICES,
@@ -427,14 +555,14 @@ class ImportScanSerializer(serializers.Serializer):
427555
verified = serializers.BooleanField(default=True)
428556
scan_type = serializers.ChoiceField(
429557
choices=ImportScanForm.SCAN_TYPE_CHOICES)
430-
tags = serializers.CharField()
431558
file = serializers.FileField()
432559
engagement = serializers.HyperlinkedRelatedField(
433560
view_name='engagement-detail',
434561
queryset=Engagement.objects.all())
435562
lead = serializers.HyperlinkedRelatedField(
436563
view_name='user-detail',
437564
queryset=User.objects.all())
565+
tags = TagListSerializerField(required=False)
438566

439567
def save(self):
440568
data = self.validated_data
@@ -456,8 +584,6 @@ def save(self):
456584
pass
457585

458586
test.save()
459-
test.tags = data['tags']
460-
461587
try:
462588
parser = import_parser_factory(data['file'],
463589
test,
@@ -516,8 +642,8 @@ def save(self):
516642

517643
item.endpoints.add(ep)
518644

519-
if item.unsaved_tags is not None:
520-
item.tags = item.unsaved_tags
645+
# if item.unsaved_tags is not None:
646+
# item.tags = item.unsaved_tags
521647
except SyntaxError:
522648
raise Exception('Parser SyntaxError')
523649

@@ -530,7 +656,7 @@ def validate_scan_data(self, value):
530656
return value
531657

532658

533-
class ReImportScanSerializer(serializers.Serializer):
659+
class ReImportScanSerializer(TaggitSerializer, serializers.Serializer):
534660
scan_date = serializers.DateField()
535661
minimum_severity = serializers.ChoiceField(
536662
choices=SEVERITY_CHOICES,
@@ -539,7 +665,7 @@ class ReImportScanSerializer(serializers.Serializer):
539665
verified = serializers.BooleanField(default=True)
540666
scan_type = serializers.ChoiceField(
541667
choices=ImportScanForm.SCAN_TYPE_CHOICES)
542-
tags = serializers.CharField()
668+
tags = TagListSerializerField(required=False)
543669
file = serializers.FileField()
544670
test = serializers.HyperlinkedRelatedField(
545671
view_name='test-detail',
@@ -650,8 +776,8 @@ def save(self):
650776
product=test.engagement.product)
651777
finding.endpoints.add(ep)
652778

653-
if item.unsaved_tags:
654-
finding.tags = item.unsaved_tags
779+
# if item.unsaved_tags:
780+
# finding.tags = item.unsaved_tags
655781

656782
to_mitigate = set(original_items) - set(new_items)
657783
for finding in to_mitigate:

dojo/endpoint/views.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ def vulnerable_endpoints(request):
4343
product = get_object_or_404(Product, id=p[0])
4444

4545
ids = get_endpoint_ids(EndpointFilter(request.GET, queryset=endpoints, user=request.user).qs)
46-
endpoints = EndpointFilter(request.GET, queryset=endpoints.filter(id__in=ids), user=request.user).order_by('host')
47-
paged_endpoints = get_page_items(request, endpoints.qs, 25)
46+
endpoints = EndpointFilter(request.GET, queryset=endpoints.filter(id__in=ids), user=request.user)
47+
endpoints_query = endpoints.qs.order_by('host')
48+
paged_endpoints = get_page_items(request, endpoints_query, 25)
4849
add_breadcrumb(title="Vulnerable Endpoints", top_level=not len(request.GET), request=request)
4950

5051
system_settings = System_Settings.objects.get()

0 commit comments

Comments
 (0)