Skip to content

Commit 31c1786

Browse files
authored
Merge pull request #321 from devEricA/master
Fixes 299, 174, 316
2 parents bc19dd3 + 6c52813 commit 31c1786

File tree

8 files changed

+206
-4
lines changed

8 files changed

+206
-4
lines changed

dojo/forms.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,6 +626,46 @@ class Meta:
626626
'review_requested_by')
627627

628628

629+
class AdHocFindingForm(forms.ModelForm):
630+
title = forms.CharField(max_length=1000)
631+
date = forms.DateField(required=True,
632+
widget=forms.TextInput(attrs={'class':
633+
'datepicker'}))
634+
cwe = forms.IntegerField(required=False)
635+
severity_options = (('Low', 'Low'), ('Medium', 'Medium'),
636+
('High', 'High'), ('Critical', 'Critical'))
637+
description = forms.CharField(widget=forms.Textarea)
638+
severity = forms.ChoiceField(
639+
choices=severity_options,
640+
error_messages={
641+
'required': 'Select valid choice: In Progress, On Hold, Completed',
642+
'invalid_choice': 'Select valid choice: Critical,High,Medium,Low'})
643+
mitigation = forms.CharField(widget=forms.Textarea)
644+
impact = forms.CharField(widget=forms.Textarea)
645+
endpoints = forms.ModelMultipleChoiceField(Endpoint.objects, required=False, label='Systems / Endpoints',
646+
widget=MultipleSelectWithPopPlusMinus(attrs={'size': '11'}))
647+
references = forms.CharField(widget=forms.Textarea, required=False)
648+
is_template = forms.BooleanField(label="Create Template?", required=False,
649+
help_text="A new finding template will be created from this finding.")
650+
651+
def clean(self):
652+
# self.fields['endpoints'].queryset = Endpoint.objects.all()
653+
cleaned_data = super(AdHocFindingForm, self).clean()
654+
if ((cleaned_data['active'] or cleaned_data['verified'])
655+
and cleaned_data['duplicate']):
656+
raise forms.ValidationError('Duplicate findings cannot be'
657+
' verified or active')
658+
if cleaned_data['false_p'] and cleaned_data['verified']:
659+
raise forms.ValidationError('False positive findings cannot '
660+
'be verified.')
661+
return cleaned_data
662+
663+
class Meta:
664+
model = Finding
665+
order = ('title', 'severity', 'endpoints', 'description', 'impact')
666+
exclude = ('reporter', 'url', 'numerical_severity', 'endpoint', 'images', 'under_review', 'reviewers',
667+
'review_requested_by')
668+
629669
class PromoteFindingForm(forms.ModelForm):
630670
title = forms.CharField(max_length=1000)
631671
date = forms.DateField(required=True,

dojo/product/urls.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@
2020
name='add_meta_data'),
2121
url(r'^product/(?P<pid>\d+)/edit_meta_data', views.edit_meta_data,
2222
name='edit_meta_data'),
23+
url(r'^product/(?P<pid>\d+)/ad_hoc_finding', views.ad_hoc_finding,
24+
name='ad_hoc_finding'),
2325
]

dojo/product/views.py

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
from pytz import timezone
1919

2020
from dojo.filters import ProductFilter, ProductFindingFilter
21-
from dojo.forms import ProductForm, EngForm, DeleteProductForm, ProductMetaDataForm, JIRAPKeyForm, JIRAFindingForm
21+
from dojo.forms import ProductForm, EngForm, DeleteProductForm, ProductMetaDataForm, JIRAPKeyForm, JIRAFindingForm, AdHocFindingForm
2222
from dojo.models import Product_Type, Finding, Product, Engagement, ScanSettings, Risk_Acceptance, Test, JIRA_PKey, \
23-
Tool_Product_Settings, Cred_User, Cred_Mapping
23+
Tool_Product_Settings, Cred_User, Cred_Mapping, Test_Type
2424
from dojo.utils import get_page_items, add_breadcrumb, get_punchcard_data, get_system_setting
2525
from custom_field.models import CustomFieldValue, CustomField
2626
from dojo.tasks import add_epic_task
@@ -383,7 +383,7 @@ def delete_product(request, pid):
383383
product = get_object_or_404(Product, pk=pid)
384384
form = DeleteProductForm(instance=product)
385385

386-
from django.contrib.admin.util import NestedObjects
386+
from django.contrib.admin.utils import NestedObjects
387387
from django.db import DEFAULT_DB_ALIAS
388388

389389
collector = NestedObjects(using=DEFAULT_DB_ALIAS)
@@ -564,3 +564,108 @@ def edit_meta_data(request, pid):
564564
{'product': prod,
565565
'product_metadata': product_metadata,
566566
})
567+
568+
569+
@user_passes_test(lambda u: u.is_staff)
570+
def ad_hoc_finding(request, pid):
571+
prod = Product.objects.get(id=pid)
572+
test = None
573+
try:
574+
eng = Engagement.objects.get(product=prod, name="Ad Hoc Engagement")
575+
tests = Test.objects.filter(engagement=eng)
576+
577+
if len(tests) != 0:
578+
test = tests[0]
579+
else:
580+
test = Test(engagement=eng, test_type=Test_Type.objects.get(name="Pen Test"),
581+
target_start=datetime.now(tz=localtz), target_end=datetime.now(tz=localtz))
582+
test.save()
583+
except:
584+
eng = Engagement(name="Ad Hoc Engagement", target_start=datetime.now(tz=localtz),
585+
target_end=datetime.now(tz=localtz), active=False, product=prod)
586+
eng.save()
587+
test = Test(engagement=eng, test_type=Test_Type.objects.get(name="Pen Test"),
588+
target_start=datetime.now(tz=localtz), target_end=datetime.now(tz=localtz))
589+
test.save()
590+
form_error = False
591+
enabled = False
592+
jform = None
593+
form = AdHocFindingForm(initial={'date': datetime.now(tz=localtz).date()})
594+
if hasattr(settings, 'ENABLE_JIRA'):
595+
if settings.ENABLE_JIRA:
596+
if JIRA_PKey.objects.filter(product=test.engagement.product).count() != 0:
597+
enabled = JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues
598+
jform = JIRAFindingForm(enabled=enabled, prefix='jiraform')
599+
else:
600+
jform = None
601+
if request.method == 'POST':
602+
form = AdHocFindingForm(request.POST)
603+
if form.is_valid():
604+
new_finding = form.save(commit=False)
605+
new_finding.test = test
606+
new_finding.reporter = request.user
607+
new_finding.numerical_severity = Finding.get_numerical_severity(
608+
new_finding.severity)
609+
if new_finding.false_p or new_finding.active is False:
610+
new_finding.mitigated = datetime.now(tz=localtz)
611+
new_finding.mitigated_by = request.user
612+
create_template = new_finding.is_template
613+
# always false now since this will be deprecated soon in favor of new Finding_Template model
614+
new_finding.is_template = False
615+
new_finding.save()
616+
new_finding.endpoints = form.cleaned_data['endpoints']
617+
new_finding.save()
618+
if 'jiraform-push_to_jira' in request.POST:
619+
jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=enabled)
620+
if jform.is_valid():
621+
add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira'))
622+
messages.add_message(request,
623+
messages.SUCCESS,
624+
'Finding added successfully.',
625+
extra_tags='alert-success')
626+
if create_template:
627+
templates = Finding_Template.objects.filter(title=new_finding.title)
628+
if len(templates) > 0:
629+
messages.add_message(request,
630+
messages.ERROR,
631+
'A finding template was not created. A template with this title already '
632+
'exists.',
633+
extra_tags='alert-danger')
634+
else:
635+
template = Finding_Template(title=new_finding.title,
636+
cwe=new_finding.cwe,
637+
severity=new_finding.severity,
638+
description=new_finding.description,
639+
mitigation=new_finding.mitigation,
640+
impact=new_finding.impact,
641+
references=new_finding.references,
642+
numerical_severity=new_finding.numerical_severity)
643+
template.save()
644+
messages.add_message(request,
645+
messages.SUCCESS,
646+
'A finding template was also created.',
647+
extra_tags='alert-success')
648+
if '_Finished' in request.POST:
649+
return HttpResponseRedirect(reverse('view_test', args=(test.id,)))
650+
else:
651+
return HttpResponseRedirect(reverse('add_findings', args=(test.id,)))
652+
else:
653+
if 'endpoints' in form.cleaned_data:
654+
form.fields['endpoints'].queryset = form.cleaned_data['endpoints']
655+
else:
656+
form.fields['endpoints'].queryset = Endpoint.objects.none()
657+
form_error = True
658+
messages.add_message(request,
659+
messages.ERROR,
660+
'The form has errors, please correct them below.',
661+
extra_tags='alert-danger')
662+
add_breadcrumb(parent=prod, title="Add Finding", top_level=False, request=request)
663+
return render(request, 'dojo/ad_hoc_findings.html',
664+
{'form': form,
665+
'temp': False,
666+
'tid' : test.id,
667+
'pid': pid,
668+
'form_error': form_error,
669+
'jform': jform,
670+
})
671+

dojo/system_settings/views.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
logger = logging.getLogger(__name__)
3535

3636

37-
@user_passes_test(lambda u: u.is_staff)
37+
@user_passes_test(lambda u: u.is_superuser)
3838
def system_settings(request):
3939
try:
4040
system_settings_obj = System_Settings.objects.get()

dojo/templates/base.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,9 @@
250250
<a href="{% url 'jira' %}"><i class="fa fa-cog fa-fw"></i>
251251
<span>Configuration</span></a>
252252
<ul class="nav nav-second-level">
253+
{% if request.user.is_superuser%}
253254
<li><a href="{% url 'system_settings' %}">System Settings </a></li>
255+
{% endif %}
254256
<li><a href="{% url 'cred' %}">Credential Manager </a></li>
255257
{% if "enable_jira"|get_system_setting %}
256258
<li><a href="{% url 'jira' %}">JIRA </a></li>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{% extends "base.html" %}
2+
{% load event_tags %}
3+
{% load static from staticfiles %}
4+
{% block content %}
5+
<div>
6+
<h3> Add findings to a test</h3>
7+
</div>
8+
<div>
9+
<form class="form-horizontal" action="{% url 'ad_hoc_finding' pid %}" method="post">
10+
{% csrf_token %}
11+
{% include "dojo/form_fields.html" with form=form %}
12+
{% if jform %}
13+
<h4> JIRA </h4>
14+
<hr>
15+
{% include "dojo/form_fields.html" with form=jform %}
16+
{% endif %}
17+
<div class="form-group">
18+
<div class="col-sm-offset-2 col-sm-10">
19+
<input class="btn btn-primary" type="submit" value="Add Another Finding"/>
20+
<input class="btn btn-primary" name="_Finished" type="submit" value="Finished"/>
21+
</div>
22+
</div>
23+
</form>
24+
</div>
25+
{% endblock %}
26+
{% block postscript %}
27+
<script type="text/javascript" src="{% static "admin/js/jquery.init.js"%}"></script>
28+
<script type="application/javascript" src="{% static "admin/js/admin/RelatedObjectLookups.js" %}"></script>
29+
<script type="application/javascript">
30+
$ = django.jQuery;
31+
$('#add_id_endpoints').attr('href', "{% url 'add_endpoint' pid %}?_popup");
32+
{% if not form_error %}
33+
$('#id_endpoints').find('option').remove();
34+
{% endif %}
35+
</script>
36+
37+
38+
{% endblock %}

dojo/templates/dojo/view_product.html

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ <h3 class="pull-left">
4545
</a>
4646
</li>
4747
{% endif %}
48+
{% if user.is_staff %}
49+
<li role="presentation">
50+
<a class="" href="{% url 'ad_hoc_finding' prod.id %}">
51+
<i class="fa fa-list-alt"></i> Add Finding
52+
</a>
53+
</li>
54+
{% endif %}
4855
{% if user.is_staff %}
4956
<li role="presentation">
5057
<a class="" href="{% url 'add_meta_data' prod.id %}">

dojo/user/views.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,10 @@ def user(request):
161161
@user_passes_test(lambda u: u.is_staff)
162162
def add_user(request):
163163
form = AddDojoUserForm()
164+
if not request.user.is_superuser:
165+
form.fields['is_staff'].widget.attrs['disabled'] = True
166+
form.fields['is_superuser'].widget.attrs['disabled'] = True
167+
form.fields['is_active'].widget.attrs['disabled'] = True
164168
contact_form = UserContactInfoForm()
165169
user = None
166170

@@ -202,6 +206,10 @@ def edit_user(request, uid):
202206
user = get_object_or_404(Dojo_User, id=uid)
203207
authed_products = Product.objects.filter(authorized_users__in=[user])
204208
form = AddDojoUserForm(instance=user, initial={'authorized_products': authed_products})
209+
if not request.user.is_superuser:
210+
form.fields['is_staff'].widget.attrs['disabled'] = True
211+
form.fields['is_superuser'].widget.attrs['disabled'] = True
212+
form.fields['is_active'].widget.attrs['disabled'] = True
205213
try:
206214
user_contact = UserContactInfo.objects.get(user=user)
207215
except UserContactInfo.DoesNotExist:

0 commit comments

Comments
 (0)