def action_history(request, cid, oid): try: ct = ContentType.objects.get_for_id(cid) obj = ct.get_object_for_this_type(pk=oid) except KeyError: raise Http404() product_id = None active_tab = None finding = None test = False object_value = None if str(ct) == "product": product_id = obj.id active_tab = "overview" object_value = Product.objects.get(id=obj.id) elif str(ct) == "engagement": object_value = Engagement.objects.get(id=obj.id) product_id = object_value.product.id active_tab = "engagements" elif str(ct) == "test": object_value = Test.objects.get(id=obj.id) product_id = object_value.engagement.product.id active_tab = "engagements" test = True elif str(ct) == "finding": object_value = Finding.objects.get(id=obj.id) product_id = object_value.test.engagement.product.id active_tab = "findings" finding = object_value elif str(ct) == "endpoint": object_value = Endpoint.objects.get(id=obj.id) product_id = object_value.product.id active_tab = "endpoints" product_tab = None if product_id: product_tab = Product_Tab(product_id, title="History", tab=active_tab) if active_tab == "engagements": if str(ct) == "engagement": product_tab.setEngagement(object_value) else: product_tab.setEngagement(object_value.engagement) history = LogEntry.objects.filter(content_type=ct, object_pk=obj.id).order_by('-timestamp') history = LogEntryFilter(request.GET, queryset=history) paged_history = get_page_items(request, history.qs, 25) return render( request, 'dojo/action_history.html', { "history": paged_history, 'product_tab': product_tab, "filtered": history, "obj": obj, "test": test, "object_value": object_value, "finding": finding })
def edit_test(request, tid): test = get_object_or_404(Test, pk=tid) form = TestForm(instance=test) if request.method == 'POST': form = TestForm(request.POST, instance=test) if form.is_valid(): new_test = form.save() tags = request.POST.getlist('tags') t = ", ".join(tags) new_test.tags = t messages.add_message(request, messages.SUCCESS, 'Test saved.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_engagement', args=(test.engagement.id,))) form.initial['target_start'] = test.target_start.date() form.initial['target_end'] = test.target_end.date() form.initial['tags'] = [tag.name for tag in test.tags] product_tab = Product_Tab(test.engagement.product.id, title="Edit Test", tab="engagements") product_tab.setEngagement(test.engagement) return render(request, 'dojo/edit_test.html', {'test': test, 'product_tab': product_tab, 'form': form, })
def delete_test(request, tid): test = get_object_or_404(Test, pk=tid) eng = test.engagement form = DeleteTestForm(instance=test) if request.method == 'POST': if 'id' in request.POST and str(test.id) == request.POST['id']: form = DeleteTestForm(request.POST, instance=test) if form.is_valid(): del test.tags test.delete() messages.add_message(request, messages.SUCCESS, 'Test and relationships removed.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_engagement', args=(eng.id,))) collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([test]) rels = collector.nested() product_tab = Product_Tab(test.engagement.product.id, title="Delete Test", tab="engagements") product_tab.setEngagement(test.engagement) return render(request, 'dojo/delete_test.html', {'test': test, 'product_tab': product_tab, 'form': form, 'rels': rels, 'deletable_objects': rels, })
def delete_engagement(request, eid): engagement = get_object_or_404(Engagement, pk=eid) product = engagement.product form = DeleteEngagementForm(instance=engagement) if request.method == 'POST': if 'id' in request.POST and str(engagement.id) == request.POST['id']: form = DeleteEngagementForm(request.POST, instance=engagement) if form.is_valid(): del engagement.tags engagement.delete() messages.add_message( request, messages.SUCCESS, 'Engagement and relationships removed.', extra_tags='alert-success') return HttpResponseRedirect(reverse("view_engagements", args=(product.id, ))) collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([engagement]) rels = collector.nested() product_tab = Product_Tab(product.id, title="Delete Engagement", tab="engagements") product_tab.setEngagement(engagement) return render(request, 'dojo/delete_engagement.html', { 'product_tab': product_tab, 'engagement': engagement, 'form': form, 'rels': rels, })
def view_test(request, tid): test = Test.objects.get(id=tid) prod = test.engagement.product auth = request.user.is_staff or request.user in prod.authorized_users.all() if not auth: # will render 403 raise PermissionDenied notes = test.notes.all() person = request.user.username findings = Finding.objects.filter(test=test).order_by('numerical_severity') stub_findings = Stub_Finding.objects.filter(test=test) cred_test = Cred_Mapping.objects.filter( test=test).select_related('cred_id').order_by('cred_id') creds = Cred_Mapping.objects.filter( engagement=test.engagement).select_related('cred_id').order_by( 'cred_id') if request.method == 'POST' and request.user.is_staff: form = NoteForm(request.POST) if form.is_valid(): new_note = form.save(commit=False) new_note.author = request.user new_note.date = timezone.now() new_note.save() test.notes.add(new_note) form = NoteForm() url = request.build_absolute_uri( reverse("view_test", args=(test.id, ))) title = "Test: %s on %s" % (test.test_type.name, test.engagement.product.name) process_notifications(request, new_note, url, title) messages.add_message(request, messages.SUCCESS, 'Note added successfully.', extra_tags='alert-success') else: form = NoteForm() fpage = get_page_items(request, findings, 25) sfpage = get_page_items(request, stub_findings, 25) show_re_upload = any(test.test_type.name in code for code in ImportScanForm.SCAN_TYPE_CHOICES) product_tab = Product_Tab(prod.id, title="Test", tab="engagements") product_tab.setEngagement(test.engagement) return render( request, 'dojo/view_test.html', { 'test': test, 'product_tab': product_tab, 'findings': fpage, 'findings_count': findings.count(), 'stub_findings': sfpage, 'form': form, 'notes': notes, 'person': person, 'request': request, 'show_re_upload': show_re_upload, 'creds': creds, 'cred_test': cred_test })
def delete_engagement(request, eid): engagement = get_object_or_404(Engagement, pk=eid) product = engagement.product form = DeleteEngagementForm(instance=engagement) if request.method == 'POST': if 'id' in request.POST and str(engagement.id) == request.POST['id']: form = DeleteEngagementForm(request.POST, instance=engagement) if form.is_valid(): del engagement.tags engagement.delete() messages.add_message( request, messages.SUCCESS, 'Engagement and relationships removed.', extra_tags='alert-success') if engagement.engagement_type == 'CI/CD': return HttpResponseRedirect(reverse("view_engagements_cicd", args=(product.id, ))) else: return HttpResponseRedirect(reverse("view_engagements", args=(product.id, ))) collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([engagement]) rels = collector.nested() product_tab = Product_Tab(product.id, title="Delete Engagement", tab="engagements") product_tab.setEngagement(engagement) return render(request, 'dojo/delete_engagement.html', { 'product_tab': product_tab, 'engagement': engagement, 'form': form, 'rels': rels, })
def action_history(request, cid, oid): try: ct = ContentType.objects.get_for_id(cid) obj = ct.get_object_for_this_type(pk=oid) except KeyError: raise Http404() product_id = None active_tab = None finding = None test = False object_value = None if str(ct) == "product": product_id = obj.id active_tab = "overview" object_value = Product.objects.get(id=obj.id) elif str(ct) == "engagement": object_value = Engagement.objects.get(id=obj.id) product_id = object_value.product.id active_tab = "engagements" elif str(ct) == "test": object_value = Test.objects.get(id=obj.id) product_id = object_value.engagement.product.id active_tab = "engagements" test = True elif str(ct) == "finding": object_value = Finding.objects.get(id=obj.id) product_id = object_value.test.engagement.product.id active_tab = "findings" finding = object_value elif str(ct) == "endpoint": object_value = Endpoint.objects.get(id=obj.id) product_id = object_value.product.id active_tab = "endpoints" product_tab = None if product_id: product_tab = Product_Tab(product_id, title="History", tab=active_tab) if active_tab == "engagements": if str(ct) == "engagement": product_tab.setEngagement(object_value) else: product_tab.setEngagement(object_value.engagement) history = LogEntry.objects.filter(content_type=ct, object_pk=obj.id).order_by('-timestamp') history = LogEntryFilter(request.GET, queryset=history) paged_history = get_page_items(request, history.qs, 25) return render(request, 'dojo/action_history.html', {"history": paged_history, 'product_tab': product_tab, "filtered": history, "obj": obj, "test": test, "object_value": object_value, "finding": finding })
def upload_risk(request, eid): eng = Engagement.objects.get(id=eid) unaccepted_findings = Finding.objects.filter(active="True", verified="True", duplicate="False", test__in=eng.test_set.all()) \ .exclude(risk_acceptance__isnull=False).order_by('title') if request.method == 'POST': form = UploadRiskForm(request.POST, request.FILES) if form.is_valid(): findings = form.cleaned_data['accepted_findings'] for finding in findings: finding.active = False finding.save() risk = form.save(commit=False) risk.owner = form.cleaned_data['owner'] risk.expiration_date = form.cleaned_data['expiration_date'] risk.accepted_by = form.cleaned_data['accepted_by'] risk.compensating_control = form.cleaned_data[ 'compensating_control'] risk.path = form.cleaned_data['path'] risk.save() # have to save before findings can be added risk.accepted_findings.set(findings) if form.cleaned_data['notes']: notes = Notes(entry=form.cleaned_data['notes'], author=request.user, date=timezone.now()) notes.save() risk.notes.add(notes) risk.save() # saving notes and findings eng.risk_acceptance.add(risk) eng.save() messages.add_message(request, messages.SUCCESS, 'Risk exception saved.', extra_tags='alert-success') return HttpResponseRedirect( reverse('view_engagement', args=(eid, ))) else: form = UploadRiskForm( initial={ 'owner': request.user, 'name': 'Ad Hoc ' + timezone.now().strftime('%b %d, %Y, %H:%M:%S') }) form.fields["accepted_findings"].queryset = unaccepted_findings product_tab = Product_Tab(eng.product.id, title="Upload Risk Exception", tab="engagements") product_tab.setEngagement(eng) return render(request, 'dojo/up_risk.html', { 'eng': eng, 'product_tab': product_tab, 'form': form })
def upload_risk(request, eid): eng = Engagement.objects.get(id=eid) # exclude the findings already accepted exclude_findings = [ finding.id for ra in eng.risk_acceptance.all() for finding in ra.accepted_findings.all() ] eng_findings = Finding.objects.filter(active="True", verified="True", duplicate="False", test__in=eng.test_set.all()) \ .exclude(id__in=exclude_findings).order_by('title') if request.method == 'POST': form = UploadRiskForm(request.POST, request.FILES) if form.is_valid(): findings = form.cleaned_data['accepted_findings'] for finding in findings: finding.active = False finding.save() risk = form.save(commit=False) risk.reporter = form.cleaned_data['reporter'] risk.expiration_date = form.cleaned_data['expiration_date'] risk.accepted_by = form.cleaned_data['accepted_by'] risk.compensating_control = form.cleaned_data['compensating_control'] risk.path = form.cleaned_data['path'] risk.save() # have to save before findings can be added risk.accepted_findings = findings if form.cleaned_data['notes']: notes = Notes( entry=form.cleaned_data['notes'], author=request.user, date=timezone.now()) notes.save() risk.notes.add(notes) risk.save() # saving notes and findings eng.risk_acceptance.add(risk) eng.save() messages.add_message( request, messages.SUCCESS, 'Risk exception saved.', extra_tags='alert-success') return HttpResponseRedirect( reverse('view_engagement', args=(eid, ))) else: form = UploadRiskForm(initial={'reporter': request.user}) form.fields["accepted_findings"].queryset = eng_findings product_tab = Product_Tab(eng.product.id, title="Upload Risk Exception", tab="engagements") product_tab.setEngagement(eng) return render(request, 'dojo/up_risk.html', { 'eng': eng, 'product_tab': product_tab, 'form': form })
def view_object_eng(request, id): object_queryset = Objects_Engagement.objects.filter(engagement=id).order_by('object_id__path', 'object_id__folder', 'object_id__artifact') engagement = Engagement.objects.get(id=id) product_tab = Product_Tab(engagement.product.id, title="Tracked Files, Folders and Artifacts on a Product", tab="engagements") product_tab.setEngagement(engagement) return render(request, 'dojo/view_objects_eng.html', { 'object_queryset': object_queryset, 'product_tab': product_tab, 'id': id })
def view_test(request, tid): test = Test.objects.get(id=tid) prod = test.engagement.product auth = request.user.is_staff or request.user in prod.authorized_users.all() if not auth: # will render 403 raise PermissionDenied notes = test.notes.all() person = request.user.username findings = Finding.objects.filter(test=test).order_by('numerical_severity') stub_findings = Stub_Finding.objects.filter(test=test) cred_test = Cred_Mapping.objects.filter(test=test).select_related('cred_id').order_by('cred_id') creds = Cred_Mapping.objects.filter(engagement=test.engagement).select_related('cred_id').order_by('cred_id') if request.method == 'POST' and request.user.is_staff: form = NoteForm(request.POST) if form.is_valid(): new_note = form.save(commit=False) new_note.author = request.user new_note.date = timezone.now() new_note.save() test.notes.add(new_note) form = NoteForm() url = request.build_absolute_uri(reverse("view_test", args=(test.id,))) title = "Test: %s on %s" % (test.test_type.name, test.engagement.product.name) process_notifications(request, new_note, url, title) messages.add_message(request, messages.SUCCESS, 'Note added successfully.', extra_tags='alert-success') else: form = NoteForm() fpage = get_page_items(request, findings, 25) sfpage = get_page_items(request, stub_findings, 25) show_re_upload = any(test.test_type.name in code for code in ImportScanForm.SCAN_TYPE_CHOICES) product_tab = Product_Tab(prod.id, title="Test", tab="engagements") product_tab.setEngagement(test.engagement) return render(request, 'dojo/view_test.html', {'test': test, 'product_tab': product_tab, 'findings': fpage, 'findings_count': findings.count(), 'stub_findings': sfpage, 'form': form, 'notes': notes, 'person': person, 'request': request, 'show_re_upload': show_re_upload, 'creds': creds, 'cred_test': cred_test })
def complete_checklist(request, eid): eng = get_object_or_404(Engagement, id=eid) try: checklist = Check_List.objects.get(engagement=eng) except: checklist = None pass add_breadcrumb(parent=eng, title="Complete checklist", top_level=False, request=request) if request.method == 'POST': tests = Test.objects.filter(engagement=eng) findings = Finding.objects.filter(test__in=tests).all() form = CheckForm(request.POST, instance=checklist, findings=findings) if form.is_valid(): cl = form.save(commit=False) try: check_l = Check_List.objects.get(engagement=eng) cl.id = check_l.id cl.save() form.save_m2m() except: cl.engagement = eng cl.save() form.save_m2m() pass messages.add_message(request, messages.SUCCESS, 'Checklist saved.', extra_tags='alert-success') return HttpResponseRedirect( reverse('view_engagement', args=(eid, ))) else: tests = Test.objects.filter(engagement=eng) findings = Finding.objects.filter(test__in=tests).all() form = CheckForm(instance=checklist, findings=findings) product_tab = Product_Tab(eng.product.id, title="Checklist", tab="engagements") product_tab.setEngagement(eng) return render( request, 'dojo/checklist.html', { 'form': form, 'product_tab': product_tab, 'eid': eng.id, 'findings': findings, })
def delete_engagement(request, eid): engagement = get_object_or_404(Engagement, pk=eid) product = engagement.product form = DeleteEngagementForm(instance=engagement) if request.method == 'POST': if 'id' in request.POST and str(engagement.id) == request.POST['id']: form = DeleteEngagementForm(request.POST, instance=engagement) if form.is_valid(): del engagement.tags engagement.delete() messages.add_message(request, messages.SUCCESS, 'Engagement and relationships removed.', extra_tags='alert-success') create_notification( event='other', title='Deletion of %s' % engagement.name, description='The engagement "%s" was deleted by %s' % (engagement.name, request.user), url=request.build_absolute_uri( reverse('view_engagements', args=(product.id, ))), recipients=[engagement.lead], icon="exclamation-triangle") if engagement.engagement_type == 'CI/CD': return HttpResponseRedirect( reverse("view_engagements_cicd", args=(product.id, ))) else: return HttpResponseRedirect( reverse("view_engagements", args=(product.id, ))) collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([engagement]) rels = collector.nested() product_tab = Product_Tab(product.id, title="Delete Engagement", tab="engagements") product_tab.setEngagement(engagement) return render( request, 'dojo/delete_engagement.html', { 'product_tab': product_tab, 'engagement': engagement, 'form': form, 'rels': rels, })
def complete_checklist(request, eid): eng = get_object_or_404(Engagement, id=eid) add_breadcrumb( parent=eng, title="Complete checklist", top_level=False, request=request) if request.method == 'POST': tests = Test.objects.filter(engagement=eng) findings = Finding.objects.filter(test__in=tests).all() form = CheckForm(request.POST, findings=findings) if form.is_valid(): cl = form.save(commit=False) try: check_l = Check_List.objects.get(engagement=eng) cl.id = check_l.id cl.save() form.save_m2m() except: cl.engagement = eng cl.save() form.save_m2m() pass messages.add_message( request, messages.SUCCESS, 'Checklist saved.', extra_tags='alert-success') return HttpResponseRedirect( reverse('view_engagement', args=(eid, ))) else: tests = Test.objects.filter(engagement=eng) findings = Finding.objects.filter(test__in=tests).all() form = CheckForm(findings=findings) product_tab = Product_Tab(eng.product.id, title="Checklist", tab="engagements") product_tab.setEngagement(eng) return render(request, 'dojo/checklist.html', { 'form': form, 'product_tab': product_tab, 'eid': eng.id, 'findings': findings, })
def delete_test(request, tid): test = get_object_or_404(Test, pk=tid) eng = test.engagement form = DeleteTestForm(instance=test) if request.method == 'POST': if 'id' in request.POST and str(test.id) == request.POST['id']: form = DeleteTestForm(request.POST, instance=test) if form.is_valid(): product = test.engagement.product test.delete() messages.add_message(request, messages.SUCCESS, 'Test and relationships removed.', extra_tags='alert-success') create_notification( event='other', title='Deletion of %s' % test.title, product=product, description='The test "%s" was deleted by %s' % (test.title, request.user), url=request.build_absolute_uri( reverse('view_engagement', args=(eng.id, ))), recipients=[test.engagement.lead], icon="exclamation-triangle") return HttpResponseRedirect( reverse('view_engagement', args=(eng.id, ))) collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([test]) rels = collector.nested() product_tab = Product_Tab(test.engagement.product.id, title="Delete Test", tab="engagements") product_tab.setEngagement(test.engagement) return render( request, 'dojo/delete_test.html', { 'test': test, 'product_tab': product_tab, 'form': form, 'rels': rels, 'deletable_objects': rels, })
def add_temp_finding(request, tid, fid): jform = None test = get_object_or_404(Test, id=tid) finding = get_object_or_404(Finding_Template, id=fid) findings = Finding_Template.objects.all() push_all_jira_issues = jira_helper.is_push_all_issues(finding) if request.method == 'POST': form = AddFindingForm(request.POST, req_resp=None, product=test.engagement.product) if jira_helper.get_jira_project(test): jform = JIRAFindingForm( push_all=jira_helper.is_push_all_issues(test), prefix='jiraform', jira_project=jira_helper.get_jira_project(test), finding_form=form) logger.debug('jform valid: %s', jform.is_valid()) if (form['active'].value() is False or form['false_p'].value() ) and form['duplicate'].value() is False: closing_disabled = Note_Type.objects.filter( is_mandatory=True, is_active=True).count() if closing_disabled != 0: error_inactive = ValidationError( 'Can not set a finding as inactive without adding all mandatory notes', code='not_active_or_false_p_true') error_false_p = ValidationError( 'Can not set a finding as false positive without adding all mandatory notes', code='not_active_or_false_p_true') if form['active'].value() is False: form.add_error('active', error_inactive) if form['false_p'].value(): form.add_error('false_p', error_false_p) messages.add_message( request, messages.ERROR, 'Can not set a finding as inactive or false positive without adding all mandatory notes', extra_tags='alert-danger') if form.is_valid(): finding.last_used = timezone.now() finding.save() new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) new_finding.date = form.cleaned_data['date'] or datetime.today() finding_helper.update_finding_status(new_finding, request.user) new_finding.save(dedupe_option=False, false_history=False) # Save and add new endpoints finding_helper.add_endpoints(new_finding, form) new_finding.save(false_history=True) if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm( request.POST, prefix='jiraform', instance=new_finding, push_all=push_all_jira_issues, jira_project=jira_helper.get_jira_project(test), finding_form=form) if jform.is_valid(): if jform.cleaned_data.get('push_to_jira'): jira_helper.push_to_jira(new_finding) else: add_error_message_to_response( 'jira form validation failed: %s' % jform.errors) messages.add_message(request, messages.SUCCESS, 'Finding from template added successfully.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_test', args=(test.id, ))) else: messages.add_message( request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') else: form = AddFindingForm(req_resp=None, product=test.engagement.product, initial={ 'active': False, 'date': timezone.now().date(), 'verified': False, 'false_p': False, 'duplicate': False, 'out_of_scope': False, 'title': finding.title, 'description': finding.description, 'cwe': finding.cwe, 'severity': finding.severity, 'mitigation': finding.mitigation, 'impact': finding.impact, 'references': finding.references, 'numerical_severity': finding.numerical_severity }) if jira_helper.get_jira_project(test): jform = JIRAFindingForm( push_all=jira_helper.is_push_all_issues(test), prefix='jiraform', jira_project=jira_helper.get_jira_project(test), finding_form=form) # logger.debug('form valid: %s', form.is_valid()) # logger.debug('jform valid: %s', jform.is_valid()) # logger.debug('form errors: %s', form.errors) # logger.debug('jform errors: %s', jform.errors) # logger.debug('jform errors: %s', vars(jform)) product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render( request, 'dojo/add_findings.html', { 'form': form, 'product_tab': product_tab, 'jform': jform, 'findings': findings, 'temp': True, 'fid': finding.id, 'tid': test.id, 'test': test, })
def re_import_scan_results(request, tid): additional_message = "When re-uploading a scan, any findings not found in original scan will be updated as " \ "mitigated. The process attempts to identify the differences, however manual verification " \ "is highly recommended." t = get_object_or_404(Test, id=tid) scan_type = t.test_type.name engagement = t.engagement form = ReImportScanForm() form.initial['tags'] = [tag.name for tag in t.tags] if request.method == "POST": form = ReImportScanForm(request.POST, request.FILES) if form.is_valid(): scan_date = form.cleaned_data['scan_date'] min_sev = form.cleaned_data['minimum_severity'] file = request.FILES['file'] scan_type = t.test_type.name active = form.cleaned_data['active'] verified = form.cleaned_data['verified'] tags = request.POST.getlist('tags') ts = ", ".join(tags) t.tags = ts try: parser = import_parser_factory(file, t, active, verified) except ValueError: raise Http404() try: items = parser.items original_items = t.finding_set.all().values_list("id", flat=True) new_items = [] mitigated_count = 0 finding_count = 0 finding_added_count = 0 reactivated_count = 0 for item in items: sev = item.severity if sev == 'Information' or sev == 'Informational': sev = 'Info' item.severity = sev if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]: continue if scan_type == 'Veracode Scan' or scan_type == 'Arachni Scan': find = Finding.objects.filter(title=item.title, test__id=t.id, severity=sev, numerical_severity=Finding.get_numerical_severity(sev), description=item.description ) else: find = Finding.objects.filter(title=item.title, test__id=t.id, severity=sev, numerical_severity=Finding.get_numerical_severity(sev), ) if len(find) == 1: find = find[0] if find.mitigated: # it was once fixed, but now back find.mitigated = None find.mitigated_by = None find.active = True find.verified = verified find.save() note = Notes(entry="Re-activated by %s re-upload." % scan_type, author=request.user) note.save() find.notes.add(note) reactivated_count += 1 new_items.append(find.id) else: item.test = t item.date = scan_date item.reporter = request.user item.last_reviewed = timezone.now() item.last_reviewed_by = request.user item.verified = verified item.active = active item.save(dedupe_option=False) finding_added_count += 1 new_items.append(item.id) find = item if hasattr(item, 'unsaved_req_resp') and len(item.unsaved_req_resp) > 0: for req_resp in item.unsaved_req_resp: if scan_type == "Arachni Scan": burp_rr = BurpRawRequestResponse( finding=item, burpRequestBase64=req_resp["req"], burpResponseBase64=req_resp["resp"], ) else: burp_rr = BurpRawRequestResponse( finding=item, burpRequestBase64=req_resp["req"].encode("utf-8"), burpResponseBase64=req_resp["resp"].encode("utf-8"), ) burp_rr.clean() burp_rr.save() if item.unsaved_request is not None and item.unsaved_response is not None: burp_rr = BurpRawRequestResponse(finding=find, burpRequestBase64=item.unsaved_request.encode("utf-8"), burpResponseBase64=item.unsaved_response.encode("utf-8"), ) burp_rr.clean() burp_rr.save() if find: finding_count += 1 for endpoint in item.unsaved_endpoints: ep, created = Endpoint.objects.get_or_create(protocol=endpoint.protocol, host=endpoint.host, path=endpoint.path, query=endpoint.query, fragment=endpoint.fragment, product=t.engagement.product) find.endpoints.add(ep) if item.unsaved_tags is not None: find.tags = item.unsaved_tags find.save() # calculate the difference to_mitigate = set(original_items) - set(new_items) for finding_id in to_mitigate: finding = Finding.objects.get(id=finding_id) finding.mitigated = datetime.combine(scan_date, timezone.now().time()) finding.mitigated_by = request.user finding.active = False finding.save() note = Notes(entry="Mitigated by %s re-upload." % scan_type, author=request.user) note.save() finding.notes.add(note) mitigated_count += 1 messages.add_message(request, messages.SUCCESS, '%s processed, a total of ' % scan_type + message(finding_count, 'finding', 'processed'), extra_tags='alert-success') if finding_added_count > 0: messages.add_message(request, messages.SUCCESS, 'A total of ' + message(finding_added_count, 'finding', 'added') + ', that are new to scan.', extra_tags='alert-success') if reactivated_count > 0: messages.add_message(request, messages.SUCCESS, 'A total of ' + message(reactivated_count, 'finding', 'reactivated') + ', that are back in scan results.', extra_tags='alert-success') if mitigated_count > 0: messages.add_message(request, messages.SUCCESS, 'A total of ' + message(mitigated_count, 'finding', 'mitigated') + '. Please manually verify each one.', extra_tags='alert-success') create_notification(event='results_added', title=str(finding_count) + " findings for " + engagement.product.name, finding_count=finding_count, test=t, engagement=engagement, url=reverse('view_test', args=(t.id,))) return HttpResponseRedirect(reverse('view_test', args=(t.id,))) except SyntaxError: messages.add_message(request, messages.ERROR, 'There appears to be an error in the XML report, please check and try again.', extra_tags='alert-danger') product_tab = Product_Tab(engagement.product.id, title="Re-upload a %s" % scan_type, tab="engagements") product_tab.setEngagement(engagement) return render(request, 'dojo/import_scan_results.html', {'form': form, 'product_tab': product_tab, 'eid': engagement.id, 'additional_message': additional_message, })
def add_findings(request, tid): test = Test.objects.get(id=tid) form_error = False enabled = False jform = None form = AddFindingForm(initial={'date': timezone.now().date()}) if get_system_setting('enable_jira') and JIRA_PKey.objects.filter(product=test.engagement.product).count() != 0: enabled = JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues jform = JIRAFindingForm(enabled=enabled, prefix='jiraform') else: jform = None if request.method == 'POST': form = AddFindingForm(request.POST) if form['active'].value() is False or form['verified'].value() is False and 'jiraform-push_to_jira' in request.POST: error = ValidationError('Findings must be active and verified to be pushed to JIRA', code='not_active_or_verified') if form['active'].value() is False: form.add_error('active', error) if form['verified'].value() is False: form.add_error('verified', error) messages.add_message(request, messages.ERROR, 'Findings must be active and verified to be pushed to JIRA', extra_tags='alert-danger') if form['severity'].value() == 'Info' and 'jiraform-push_to_jira' in request.POST: error = ValidationError('Findings with Informational severity cannot be pushed to JIRA.', code='info-severity-to-jira') if form.is_valid(): new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) if new_finding.false_p or new_finding.active is False: new_finding.mitigated = timezone.now() new_finding.mitigated_by = request.user create_template = new_finding.is_template # always false now since this will be deprecated soon in favor of new Finding_Template model new_finding.is_template = False new_finding.save(dedupe_option=False) new_finding.endpoints = form.cleaned_data['endpoints'] new_finding.save(false_history=True) if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=enabled) if jform.is_valid(): add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira')) messages.add_message(request, messages.SUCCESS, 'Finding added successfully.', extra_tags='alert-success') if create_template: templates = Finding_Template.objects.filter(title=new_finding.title) if len(templates) > 0: messages.add_message(request, messages.ERROR, 'A finding template was not created. A template with this title already ' 'exists.', extra_tags='alert-danger') else: template = Finding_Template(title=new_finding.title, cwe=new_finding.cwe, severity=new_finding.severity, description=new_finding.description, mitigation=new_finding.mitigation, impact=new_finding.impact, references=new_finding.references, numerical_severity=new_finding.numerical_severity) template.save() messages.add_message(request, messages.SUCCESS, 'A finding template was also created.', extra_tags='alert-success') if '_Finished' in request.POST: return HttpResponseRedirect(reverse('view_test', args=(test.id,))) else: return HttpResponseRedirect(reverse('add_findings', args=(test.id,))) else: if 'endpoints' in form.cleaned_data: form.fields['endpoints'].queryset = form.cleaned_data['endpoints'] else: form.fields['endpoints'].queryset = Endpoint.objects.none() form_error = True messages.add_message(request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render(request, 'dojo/add_findings.html', {'form': form, 'product_tab': product_tab, 'test': test, 'temp': False, 'tid': tid, 'form_error': form_error, 'jform': jform, })
def add_risk_acceptance(request, eid, fid=None): eng = get_object_or_404(Engagement, id=eid) finding = None if fid: finding = get_object_or_404(Finding, id=fid) if not eng.product.enable_full_risk_acceptance: raise PermissionDenied() if request.method == 'POST': form = RiskAcceptanceForm(request.POST, request.FILES) if form.is_valid(): # first capture notes param as it cannot be saved directly as m2m notes = None if form.cleaned_data['notes']: notes = Notes( entry=form.cleaned_data['notes'], author=request.user, date=timezone.now()) notes.save() del form.cleaned_data['notes'] try: # we sometimes see a weird exception here, but are unable to reproduce. # we add some logging in case it happens risk_acceptance = form.save() except Exception as e: logger.debug(vars(request.POST)) logger.error(vars(form)) logger.exception(e) raise # attach note to risk acceptance object now in database if notes: risk_acceptance.notes.add(notes) eng.risk_acceptance.add(risk_acceptance) findings = form.cleaned_data['accepted_findings'] risk_acceptance = ra_helper.add_findings_to_risk_acceptance(risk_acceptance, findings) messages.add_message( request, messages.SUCCESS, 'Risk acceptance saved.', extra_tags='alert-success') return redirect_to_return_url_or_else(request, reverse('view_engagement', args=(eid, ))) else: risk_acceptance_title_suggestion = 'Accept: %s' % finding form = RiskAcceptanceForm(initial={'owner': request.user, 'name': risk_acceptance_title_suggestion}) finding_choices = Finding.objects.filter(duplicate=False, test__engagement=eng).filter(NOT_ACCEPTED_FINDINGS_QUERY).order_by('title') form.fields['accepted_findings'].queryset = finding_choices if fid: form.fields['accepted_findings'].initial = {fid} product_tab = Product_Tab(eng.product.id, title="Risk Acceptance", tab="engagements") product_tab.setEngagement(eng) return render(request, 'dojo/add_risk_acceptance.html', { 'eng': eng, 'product_tab': product_tab, 'form': form })
def add_findings(request, tid): test = Test.objects.get(id=tid) form_error = False enabled = False jform = None form = AddFindingForm(initial={'date': timezone.now().date()}) if get_system_setting('enable_jira') and JIRA_PKey.objects.filter(product=test.engagement.product).count() != 0: enabled = JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues jform = JIRAFindingForm(enabled=enabled, prefix='jiraform') else: jform = None if request.method == 'POST': form = AddFindingForm(request.POST) if form['active'].value() is False or form['verified'].value() is False and 'jiraform-push_to_jira' in request.POST: error = ValidationError('Findings must be active and verified to be pushed to JIRA', code='not_active_or_verified') if form['active'].value() is False: form.add_error('active', error) if form['verified'].value() is False: form.add_error('verified', error) messages.add_message(request, messages.ERROR, 'Findings must be active and verified to be pushed to JIRA', extra_tags='alert-danger') if form['severity'].value() == 'Info' and 'jiraform-push_to_jira' in request.POST: error = ValidationError('Findings with Informational severity cannot be pushed to JIRA.', code='info-severity-to-jira') if form.is_valid(): new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) if new_finding.false_p or new_finding.active is False: new_finding.mitigated = timezone.now() new_finding.mitigated_by = request.user create_template = new_finding.is_template # always false now since this will be deprecated soon in favor of new Finding_Template model new_finding.is_template = False new_finding.save(dedupe_option=False) new_finding.endpoints.set(form.cleaned_data['endpoints']) new_finding.save(false_history=True) create_notification(event='other', title='Addition of %s' % new_finding.title, description='Finding "%s" was added by %s' % (new_finding.title, request.user), url=request.build_absolute_uri(reverse('view_finding', args=(new_finding.id,))), icon="exclamation-triangle") if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=enabled) if jform.is_valid(): add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira')) messages.add_message(request, messages.SUCCESS, 'Finding added successfully.', extra_tags='alert-success') if create_template: templates = Finding_Template.objects.filter(title=new_finding.title) if len(templates) > 0: messages.add_message(request, messages.ERROR, 'A finding template was not created. A template with this title already ' 'exists.', extra_tags='alert-danger') else: template = Finding_Template(title=new_finding.title, cwe=new_finding.cwe, severity=new_finding.severity, description=new_finding.description, mitigation=new_finding.mitigation, impact=new_finding.impact, references=new_finding.references, numerical_severity=new_finding.numerical_severity) template.save() messages.add_message(request, messages.SUCCESS, 'A finding template was also created.', extra_tags='alert-success') if '_Finished' in request.POST: return HttpResponseRedirect(reverse('view_test', args=(test.id,))) else: return HttpResponseRedirect(reverse('add_findings', args=(test.id,))) else: if 'endpoints' in form.cleaned_data: form.fields['endpoints'].queryset = form.cleaned_data['endpoints'] else: form.fields['endpoints'].queryset = Endpoint.objects.none() form_error = True messages.add_message(request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render(request, 'dojo/add_findings.html', {'form': form, 'product_tab': product_tab, 'test': test, 'temp': False, 'tid': tid, 'form_error': form_error, 'jform': jform, })
def ad_hoc_finding(request, pid): prod = Product.objects.get(id=pid) test = None try: eng = Engagement.objects.get(product=prod, name="Ad Hoc Engagement") tests = Test.objects.filter(engagement=eng) if len(tests) != 0: test = tests[0] else: test = Test(engagement=eng, test_type=Test_Type.objects.get(name="Pen Test"), target_start=timezone.now(), target_end=timezone.now()) test.save() except: eng = Engagement(name="Ad Hoc Engagement", target_start=timezone.now(), target_end=timezone.now(), active=False, product=prod) eng.save() test = Test(engagement=eng, test_type=Test_Type.objects.get(name="Pen Test"), target_start=timezone.now(), target_end=timezone.now()) test.save() form_error = False enabled = False jform = None form = AdHocFindingForm(initial={'date': timezone.now().date()}) if get_system_setting('enable_jira'): if JIRA_PKey.objects.filter( product=test.engagement.product).count() != 0: enabled = JIRA_PKey.objects.get( product=test.engagement.product).push_all_issues jform = JIRAFindingForm(enabled=enabled, prefix='jiraform') else: jform = None if request.method == 'POST': form = AdHocFindingForm(request.POST) if form.is_valid(): new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) if new_finding.false_p or new_finding.active is False: new_finding.mitigated = timezone.now() new_finding.mitigated_by = request.user create_template = new_finding.is_template # always false now since this will be deprecated soon in favor of new Finding_Template model new_finding.is_template = False new_finding.save() new_finding.endpoints = form.cleaned_data['endpoints'] new_finding.save() if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=enabled) if jform.is_valid(): add_issue_task.delay( new_finding, jform.cleaned_data.get('push_to_jira')) messages.add_message(request, messages.SUCCESS, 'Finding added successfully.', extra_tags='alert-success') if create_template: templates = Finding_Template.objects.filter( title=new_finding.title) if len(templates) > 0: messages.add_message( request, messages.ERROR, 'A finding template was not created. A template with this title already ' 'exists.', extra_tags='alert-danger') else: template = Finding_Template( title=new_finding.title, cwe=new_finding.cwe, severity=new_finding.severity, description=new_finding.description, mitigation=new_finding.mitigation, impact=new_finding.impact, references=new_finding.references, numerical_severity=new_finding.numerical_severity) template.save() messages.add_message( request, messages.SUCCESS, 'A finding template was also created.', extra_tags='alert-success') if '_Finished' in request.POST: return HttpResponseRedirect( reverse('view_test', args=(test.id, ))) else: return HttpResponseRedirect( reverse('add_findings', args=(test.id, ))) else: if 'endpoints' in form.cleaned_data: form.fields['endpoints'].queryset = form.cleaned_data[ 'endpoints'] else: form.fields['endpoints'].queryset = Endpoint.objects.none() form_error = True messages.add_message( request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') product_tab = Product_Tab(pid, title="Add Finding", tab="engagements") product_tab.setEngagement(eng) return render( request, 'dojo/ad_hoc_findings.html', { 'form': form, 'product_tab': product_tab, 'temp': False, 'tid': test.id, 'pid': pid, 'form_error': form_error, 'jform': jform, })
def view_engagement(request, eid): eng = get_object_or_404(Engagement, id=eid) tests = Test.objects.filter(engagement=eng).order_by('test_type__name') prod = eng.product auth = request.user.is_staff or request.user in prod.authorized_users.all() risks_accepted = eng.risk_acceptance.all() preset_test_type = None network = None if eng.preset: preset_test_type = eng.preset.test_type.all() network = eng.preset.network_locations.all() system_settings = System_Settings.objects.get() if not auth: # will render 403 raise PermissionDenied try: jissue = JIRA_Issue.objects.get(engagement=eng) except: jissue = None pass try: jconf = JIRA_PKey.objects.get(product=eng.product).conf except: jconf = None pass exclude_findings = [ finding.id for ra in eng.risk_acceptance.all() for finding in ra.accepted_findings.all() ] eng_findings = Finding.objects.filter(test__in=eng.test_set.all()) \ .exclude(id__in=exclude_findings).order_by('title') try: check = Check_List.objects.get(engagement=eng) except: check = None pass form = DoneForm() if request.method == 'POST' and request.user.is_staff: eng.progress = 'check_list' eng.save() creds = Cred_Mapping.objects.filter( product=eng.product).select_related('cred_id').order_by('cred_id') cred_eng = Cred_Mapping.objects.filter( engagement=eng.id).select_related('cred_id').order_by('cred_id') add_breadcrumb(parent=eng, top_level=False, request=request) if hasattr(settings, 'ENABLE_DEDUPLICATION'): if settings.ENABLE_DEDUPLICATION: enabled = True findings = Finding.objects.filter( test__engagement=eng, duplicate=False) else: enabled = False findings = None else: enabled = False findings = None if findings is not None: fpage = get_page_items(request, findings, 15) else: fpage = None # ---------- try: start_date = Finding.objects.filter( test__engagement__product=eng.product).order_by('date')[:1][0].date except: start_date = timezone.now() end_date = timezone.now() risk_acceptances = Risk_Acceptance.objects.filter( engagement__in=Engagement.objects.filter(product=eng.product)) accepted_findings = [ finding for ra in risk_acceptances for finding in ra.accepted_findings.all() ] title = "" if eng.engagement_type == "CI/CD": title = " CI/CD" product_tab = Product_Tab(prod.id, title="View" + title + " Engagement", tab="engagements") product_tab.setEngagement(eng) return render( request, 'dojo/view_eng.html', { 'eng': eng, 'product_tab': product_tab, 'system_settings': system_settings, 'tests': tests, 'findings': fpage, 'enabled': enabled, 'check': check, 'threat': eng.tmodel_path, 'risk': eng.risk_path, 'form': form, 'risks_accepted': risks_accepted, 'can_add_risk': len(eng_findings), 'jissue': jissue, 'jconf': jconf, 'accepted_findings': accepted_findings, 'start_date': start_date, 'creds': creds, 'cred_eng': cred_eng, 'network': network, 'preset_test_type': preset_test_type })
def view_risk(request, eid, raid): risk_approval = get_object_or_404(Risk_Acceptance, pk=raid) eng = get_object_or_404(Engagement, pk=eid) if (request.user.is_staff or request.user in eng.product.authorized_users.all()): pass else: raise PermissionDenied a_file = risk_approval.path if request.method == 'POST': note_form = NoteForm(request.POST) if note_form.is_valid(): new_note = note_form.save(commit=False) new_note.author = request.user new_note.date = timezone.now() new_note.save() risk_approval.notes.add(new_note) messages.add_message(request, messages.SUCCESS, 'Note added successfully.', extra_tags='alert-success') if 'delete_note' in request.POST: note = get_object_or_404(Notes, pk=request.POST['delete_note_id']) if note.author.username == request.user.username: risk_approval.notes.remove(note) note.delete() messages.add_message(request, messages.SUCCESS, 'Note deleted successfully.', extra_tags='alert-success') else: messages.add_message( request, messages.ERROR, "Since you are not the note's author, it was not deleted.", extra_tags='alert-danger') if 'remove_finding' in request.POST: finding = get_object_or_404(Finding, pk=request.POST['remove_finding_id']) risk_approval.accepted_findings.remove(finding) finding.active = True finding.save() messages.add_message(request, messages.SUCCESS, 'Finding removed successfully.', extra_tags='alert-success') if 'replace_file' in request.POST: replace_form = ReplaceRiskAcceptanceForm(request.POST, request.FILES, instance=risk_approval) if replace_form.is_valid(): risk_approval.path.delete(save=False) risk_approval.path = replace_form.cleaned_data['path'] risk_approval.save() messages.add_message(request, messages.SUCCESS, 'File replaced successfully.', extra_tags='alert-success') if 'add_findings' in request.POST: add_findings_form = AddFindingsRiskAcceptanceForm( request.POST, request.FILES, instance=risk_approval) if add_findings_form.is_valid(): findings = add_findings_form.cleaned_data['accepted_findings'] for finding in findings: finding.active = False finding.save() risk_approval.accepted_findings.add(finding) risk_approval.save() messages.add_message(request, messages.SUCCESS, 'Finding%s added successfully.' % ('s' if len(findings) > 1 else ''), extra_tags='alert-success') note_form = NoteForm() replace_form = ReplaceRiskAcceptanceForm() add_findings_form = AddFindingsRiskAcceptanceForm() exclude_findings = [ finding.id for ra in eng.risk_acceptance.all() for finding in ra.accepted_findings.all() ] findings = Finding.objects.filter(test__in=eng.test_set.all()) \ .exclude(id__in=exclude_findings).order_by("title") add_fpage = get_page_items(request, findings, 10, 'apage') add_findings_form.fields[ "accepted_findings"].queryset = add_fpage.object_list fpage = get_page_items( request, risk_approval.accepted_findings.order_by('numerical_severity'), 15) authorized = (request.user == risk_approval.reporter.username or request.user.is_staff) product_tab = Product_Tab(eng.product.id, title="Risk Exception", tab="engagements") product_tab.setEngagement(eng) return render( request, 'dojo/view_risk.html', { 'risk_approval': risk_approval, 'product_tab': product_tab, 'accepted_findings': fpage, 'notes': risk_approval.notes.all(), 'a_file': a_file, 'eng': eng, 'note_form': note_form, 'replace_form': replace_form, 'add_findings_form': add_findings_form, 'show_add_findings_form': len(findings), 'request': request, 'add_findings': add_fpage, 'authorized': authorized, })
def add_findings(request, tid): test = Test.objects.get(id=tid) form_error = False jform = None form = AddFindingForm(initial={'date': timezone.now().date()}, req_resp=None) push_all_jira_issues = False use_jira = get_system_setting( 'enable_jira') and test.engagement.product.jira_pkey is not None if request.method == 'POST': form = AddFindingForm(request.POST, req_resp=None) if (form['active'].value() is False or form['verified'].value() is False) \ and 'jiraform-push_to_jira' in request.POST: error = ValidationError( 'Findings must be active and verified to be pushed to JIRA', code='not_active_or_verified') if form['active'].value() is False: form.add_error('active', error) if form['verified'].value() is False: form.add_error('verified', error) messages.add_message( request, messages.ERROR, 'Findings must be active and verified to be pushed to JIRA', extra_tags='alert-danger') if form['severity'].value( ) == 'Info' and 'jiraform-push_to_jira' in request.POST: error = ValidationError( 'Findings with Informational severity cannot be pushed to JIRA.', code='info-severity-to-jira') if (form['active'].value() is False or form['false_p'].value() ) and form['duplicate'].value() is False: closing_disabled = Note_Type.objects.filter( is_mandatory=True, is_active=True).count() if closing_disabled != 0: error_inactive = ValidationError( 'Can not set a finding as inactive without adding all mandatory notes', code='inactive_without_mandatory_notes') error_false_p = ValidationError( 'Can not set a finding as false positive without adding all mandatory notes', code='false_p_without_mandatory_notes') if form['active'].value() is False: form.add_error('active', error_inactive) if form['false_p'].value(): form.add_error('false_p', error_false_p) messages.add_message( request, messages.ERROR, 'Can not set a finding as inactive or false positive without adding all mandatory notes', extra_tags='alert-danger') if use_jira: jform = JIRAFindingForm( request.POST, prefix='jiraform', push_all=push_all_jira_issues, jira_pkey=test.engagement.product.jira_pkey) if form.is_valid() and (jform is None or jform.is_valid()): if jform: logger.debug('jform.jira_issue: %s', jform.cleaned_data.get('jira_issue')) logger.debug('jform.push_to_jira: %s', jform.cleaned_data.get('push_to_jira')) new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) if new_finding.false_p or new_finding.active is False: new_finding.mitigated = timezone.now() new_finding.mitigated_by = request.user new_finding.is_Mitigated = True create_template = new_finding.is_template # always false now since this will be deprecated soon in favor of new Finding_Template model new_finding.is_template = False new_finding.save(dedupe_option=False, push_to_jira=False) for ep in form.cleaned_data['endpoints']: eps, created = Endpoint_Status.objects.get_or_create( finding=new_finding, endpoint=ep) ep.endpoint_status.add(eps) new_finding.endpoints.add(ep) new_finding.endpoint_status.add(eps) # Push to jira? push_to_jira = False jira_message = None if jform and jform.is_valid(): # Push to Jira? push_to_jira = push_all_jira_issues or jform.cleaned_data.get( 'push_to_jira') # if the jira issue key was changed, update database new_jira_issue_key = jform.cleaned_data.get('jira_issue') if new_finding.has_jira_issue(): jira_issue = new_finding.jira_issue # everything in DD around JIRA integration is based on the internal id of the issue in JIRA # instead of on the public jira issue key. # I have no idea why, but it means we have to retrieve the issue from JIRA to get the internal JIRA id. # we can assume the issue exist, which is already checked in the validation of the jform if not new_jira_issue_key: finding_unlink_jira(request, new_finding) jira_message = 'Link to JIRA issue removed successfully.' elif new_jira_issue_key != new_finding.jira_issue.jira_key: finding_unlink_jira(request, new_finding) finding_link_jira(request, new_finding, new_jira_issue_key) jira_message = 'Changed JIRA link successfully.' else: logger.debug('finding has no jira issue yet') if new_jira_issue_key: logger.debug( 'finding has no jira issue yet, but jira issue specified in request. trying to link.' ) finding_link_jira(request, new_finding, new_jira_issue_key) jira_message = 'Linked a JIRA issue successfully.' new_finding.save(false_history=True, push_to_jira=push_to_jira) create_notification(event='other', title='Addition of %s' % new_finding.title, description='Finding "%s" was added by %s' % (new_finding.title, request.user), url=request.build_absolute_uri( reverse('view_finding', args=(new_finding.id, ))), icon="exclamation-triangle") if 'request' in form.cleaned_data or 'response' in form.cleaned_data: burp_rr = BurpRawRequestResponse( finding=new_finding, burpRequestBase64=base64.b64encode( form.cleaned_data['request'].encode()), burpResponseBase64=base64.b64encode( form.cleaned_data['response'].encode()), ) burp_rr.clean() burp_rr.save() if create_template: templates = Finding_Template.objects.filter( title=new_finding.title) if len(templates) > 0: messages.add_message( request, messages.ERROR, 'A finding template was not created. A template with this title already ' 'exists.', extra_tags='alert-danger') else: template = Finding_Template( title=new_finding.title, cwe=new_finding.cwe, severity=new_finding.severity, description=new_finding.description, mitigation=new_finding.mitigation, impact=new_finding.impact, references=new_finding.references, numerical_severity=new_finding.numerical_severity) template.save() messages.add_message( request, messages.SUCCESS, 'A finding template was also created.', extra_tags='alert-success') if '_Finished' in request.POST: return HttpResponseRedirect( reverse('view_test', args=(test.id, ))) else: return HttpResponseRedirect( reverse('add_findings', args=(test.id, ))) else: if 'endpoints' in form.cleaned_data: form.fields['endpoints'].queryset = form.cleaned_data[ 'endpoints'] else: form.fields['endpoints'].queryset = Endpoint.objects.none() form_error = True messages.add_message( request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') else: if use_jira: push_all_jira_issues = test.engagement.product.jira_pkey.push_all_issues jform = JIRAFindingForm( push_all=push_all_jira_issues, prefix='jiraform', jira_pkey=test.engagement.product.jira_pkey) product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render( request, 'dojo/add_findings.html', { 'form': form, 'product_tab': product_tab, 'test': test, 'temp': False, 'tid': tid, 'form_error': form_error, 'jform': jform, })
def generate_report(request, obj): user = Dojo_User.objects.get(id=request.user.id) product_type = None product = None engagement = None test = None endpoint = None endpoints = None endpoint_all_findings = None endpoint_monthly_counts = None endpoint_active_findings = None accepted_findings = None open_findings = None closed_findings = None verified_findings = None report_title = None report_subtitle = None report_info = "Generated By %s on %s" % ( user.get_full_name(), (timezone.now().strftime("%m/%d/%Y %I:%M%p %Z"))) if type(obj).__name__ == "Product": if request.user.is_staff or request.user in obj.authorized_users.all(): pass # user is authorized for this product else: raise PermissionDenied elif type(obj).__name__ == "Endpoint": if request.user.is_staff or request.user in obj.product.authorized_users.all(): pass # user is authorized for this product else: raise PermissionDenied elif type(obj).__name__ == "QuerySet": # authorization taken care of by only selecting findings from product user is authed to see pass else: if not request.user.is_staff: raise PermissionDenied report_format = request.GET.get('report_type', 'AsciiDoc') include_finding_notes = int(request.GET.get('include_finding_notes', 0)) include_finding_images = int(request.GET.get('include_finding_images', 0)) include_executive_summary = int(request.GET.get('include_executive_summary', 0)) include_table_of_contents = int(request.GET.get('include_table_of_contents', 0)) generate = "_generate" in request.GET report_name = str(obj) report_type = type(obj).__name__ add_breadcrumb(title="Generate Report", top_level=False, request=request) if type(obj).__name__ == "Product_Type": product_type = obj filename = "product_type_finding_report.pdf" template = "dojo/product_type_pdf_report.html" report_name = "Product Type Report: " + str(product_type) report_title = "Product Type Report" report_subtitle = str(product_type) findings = ReportFindingFilter(request.GET, queryset=Finding.objects.filter( test__engagement__product__prod_type=product_type).distinct().prefetch_related('test', 'test__engagement__product', 'test__engagement__product__prod_type')) products = Product.objects.filter(prod_type=product_type, engagement__test__finding__in=findings.qs).distinct() engagements = Engagement.objects.filter(product__prod_type=product_type, test__finding__in=findings.qs).distinct() tests = Test.objects.filter(engagement__product__prod_type=product_type, finding__in=findings.qs).distinct() if findings: start_date = timezone.make_aware(datetime.combine(findings.qs.last().date, datetime.min.time())) else: start_date = timezone.now() end_date = timezone.now() r = relativedelta(end_date, start_date) months_between = (r.years * 12) + r.months # include current month months_between += 1 endpoint_monthly_counts = get_period_counts_legacy(findings.qs.order_by('numerical_severity'), findings.qs.order_by('numerical_severity'), None, months_between, start_date, relative_delta='months') context = {'product_type': product_type, 'products': products, 'engagements': engagements, 'tests': tests, 'report_name': report_name, 'endpoint_opened_per_month': endpoint_monthly_counts[ 'opened_per_period'] if endpoint_monthly_counts is not None else [], 'endpoint_active_findings': findings.qs.order_by('numerical_severity'), 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': 'Generate Report', 'host': report_url_resolver(request), 'user_id': request.user.id} elif type(obj).__name__ == "Product": product = obj filename = "product_finding_report.pdf" template = "dojo/product_pdf_report.html" report_name = "Product Report: " + str(product) report_title = "Product Report" report_subtitle = str(product) findings = ReportFindingFilter(request.GET, queryset=Finding.objects.filter( test__engagement__product=product).distinct().prefetch_related('test', 'test__engagement__product', 'test__engagement__product__prod_type')) ids = set(finding.id for finding in findings.qs) engagements = Engagement.objects.filter(test__finding__id__in=ids).distinct() tests = Test.objects.filter(finding__id__in=ids).distinct() ids = get_endpoint_ids(Endpoint.objects.filter(product=product).distinct()) endpoints = Endpoint.objects.filter(id__in=ids) context = {'product': product, 'engagements': engagements, 'tests': tests, 'report_name': report_name, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': 'Generate Report', 'endpoints': endpoints, 'host': report_url_resolver(request), 'user_id': request.user.id} elif type(obj).__name__ == "Engagement": engagement = obj findings = ReportFindingFilter(request.GET, queryset=Finding.objects.filter(test__engagement=engagement, ).prefetch_related('test', 'test__engagement__product', 'test__engagement__product__prod_type').distinct()) report_name = "Engagement Report: " + str(engagement) filename = "engagement_finding_report.pdf" template = 'dojo/engagement_pdf_report.html' report_title = "Engagement Report" report_subtitle = str(engagement) ids = set(finding.id for finding in findings.qs) tests = Test.objects.filter(finding__id__in=ids).distinct() ids = get_endpoint_ids(Endpoint.objects.filter(product=engagement.product).distinct()) endpoints = Endpoint.objects.filter(id__in=ids) context = {'engagement': engagement, 'tests': tests, 'report_name': report_name, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': 'Generate Report', 'host': report_url_resolver(request), 'user_id': request.user.id, 'endpoints': endpoints} elif type(obj).__name__ == "Test": test = obj findings = ReportFindingFilter(request.GET, queryset=Finding.objects.filter(test=test).prefetch_related('test', 'test__engagement__product', 'test__engagement__product__prod_type').distinct()) filename = "test_finding_report.pdf" template = "dojo/test_pdf_report.html" report_name = "Test Report: " + str(test) report_title = "Test Report" report_subtitle = str(test) context = {'test': test, 'report_name': report_name, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': 'Generate Report', 'host': report_url_resolver(request), 'user_id': request.user.id} elif type(obj).__name__ == "Endpoint": endpoint = obj host = endpoint.host_no_port report_name = "Endpoint Report: " + host report_type = "Endpoint" endpoints = Endpoint.objects.filter(host__regex="^" + host + ":?", product=endpoint.product).distinct() filename = "endpoint_finding_report.pdf" template = 'dojo/endpoint_pdf_report.html' report_title = "Endpoint Report" report_subtitle = host findings = ReportFindingFilter(request.GET, queryset=Finding.objects.filter(endpoints__in=endpoints, ).prefetch_related('test', 'test__engagement__product', 'test__engagement__product__prod_type').distinct()) context = {'endpoint': endpoint, 'endpoints': endpoints, 'report_name': report_name, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': get_system_setting('team_name'), 'title': 'Generate Report', 'host': report_url_resolver(request), 'user_id': request.user.id} elif type(obj).__name__ == "QuerySet": findings = ReportAuthedFindingFilter(request.GET, queryset=obj.prefetch_related('test', 'test__engagement__product', 'test__engagement__product__prod_type').distinct(), user=request.user) filename = "finding_report.pdf" report_name = 'Finding' report_type = 'Finding' template = 'dojo/finding_pdf_report.html' report_title = "Finding Report" report_subtitle = '' context = {'findings': findings.qs.order_by('numerical_severity'), 'report_name': report_name, 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': 'Generate Report', 'host': report_url_resolver(request), 'user_id': request.user.id} else: raise Http404() report_form = ReportOptionsForm() if generate: report_form = ReportOptionsForm(request.GET) if report_format == 'AsciiDoc': return render(request, 'dojo/asciidoc_report.html', {'product_type': product_type, 'product': product, 'engagement': engagement, 'test': test, 'endpoint': endpoint, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': 'Generate Report', 'user_id': request.user.id, 'host': report_url_resolver(request), }) elif report_format == 'PDF': if 'regen' in request.GET: # we should already have a report object, lets get and use it report = get_object_or_404(Report, id=request.GET['regen']) report.datetime = timezone.now() report.status = 'requested' if report.requester.username != request.user.username: report.requester = request.user else: # lets create the report object and send it in to celery task report = Report(name=report_name, type=report_type, format='PDF', requester=request.user, task_id='tbd', options=request.path + "?" + request.GET.urlencode()) report.save() async_pdf_report.delay(report=report, template=template, filename=filename, report_title=report_title, report_subtitle=report_subtitle, report_info=report_info, context=context, uri=request.build_absolute_uri(report.get_url())) messages.add_message(request, messages.SUCCESS, 'Your report is building.', extra_tags='alert-success') return HttpResponseRedirect(reverse('reports')) elif report_format == 'HTML': return render(request, template, {'product_type': product_type, 'product': product, 'engagement': engagement, 'report_name': report_name, 'test': test, 'endpoint': endpoint, 'endpoints': endpoints, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': 'Generate Report', 'user_id': request.user.id, 'host': "", }) else: raise Http404() paged_findings = get_page_items(request, findings.qs.order_by('numerical_severity'), 25) product_tab = None if engagement: product_tab = Product_Tab(engagement.product.id, title="Engagement Report", tab="engagements") product_tab.setEngagement(engagement) elif test: product_tab = Product_Tab(test.engagement.product.id, title="Test Report", tab="engagements") product_tab.setEngagement(test.engagement) elif product: product_tab = Product_Tab(product.id, title="Product Report", tab="findings") elif endpoints: product_tab = Product_Tab(endpoint.product.id, title="Endpoint Report", tab="endpoints") return render(request, 'dojo/request_report.html', {'product_type': product_type, 'product': product, 'product_tab': product_tab, 'engagement': engagement, 'test': test, 'endpoint': endpoint, 'findings': findings, 'paged_findings': paged_findings, 'report_form': report_form, })
def import_scan_results(request, eid=None, pid=None): engagement = None form = ImportScanForm() cred_form = CredMappingForm() finding_count = 0 if eid: engagement = get_object_or_404(Engagement, id=eid) cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(engagement=engagement).order_by('cred_id') if request.method == "POST": form = ImportScanForm(request.POST, request.FILES) cred_form = CredMappingForm(request.POST) cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter( engagement=engagement).order_by('cred_id') if form.is_valid(): # Allows for a test to be imported with an engagement created on the fly if engagement is None: engagement = Engagement() product = get_object_or_404(Product, id=pid) engagement.name = "AdHoc Import - " + strftime("%a, %d %b %Y %X", timezone.now().timetuple()) engagement.threat_model = False engagement.api_test = False engagement.pen_test = False engagement.check_list = False engagement.target_start = timezone.now().date() engagement.target_end = timezone.now().date() engagement.product = product engagement.active = True engagement.status = 'In Progress' engagement.save() file = request.FILES['file'] scan_date = form.cleaned_data['scan_date'] min_sev = form.cleaned_data['minimum_severity'] active = form.cleaned_data['active'] verified = form.cleaned_data['verified'] scan_type = request.POST['scan_type'] if not any(scan_type in code for code in ImportScanForm.SCAN_TYPE_CHOICES): raise Http404() tt, t_created = Test_Type.objects.get_or_create(name=scan_type) # will save in development environment environment, env_created = Development_Environment.objects.get_or_create( name="Development") t = Test( engagement=engagement, test_type=tt, target_start=scan_date, target_end=scan_date, environment=environment, percent_complete=100) t.lead = request.user t.full_clean() t.save() tags = request.POST.getlist('tags') ts = ", ".join(tags) t.tags = ts # Save the credential to the test if cred_form.is_valid(): if cred_form.cleaned_data['cred_user']: # Select the credential mapping object from the selected list and only allow if the credential is associated with the product cred_user = Cred_Mapping.objects.filter( pk=cred_form.cleaned_data['cred_user'].id, engagement=eid).first() new_f = cred_form.save(commit=False) new_f.test = t new_f.cred_id = cred_user.cred_id new_f.save() parser = import_parser_factory(file, t) try: for item in parser.items: print "item blowup" print item sev = item.severity if sev == 'Information' or sev == 'Informational': sev = 'Info' item.severity = sev if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]: continue item.test = t if item.date == timezone.now().date(): item.date = t.target_start item.reporter = request.user item.last_reviewed = timezone.now() item.last_reviewed_by = request.user item.active = active item.verified = verified item.save(dedupe_option=False, false_history=True) if hasattr(item, 'unsaved_req_resp') and len( item.unsaved_req_resp) > 0: for req_resp in item.unsaved_req_resp: burp_rr = BurpRawRequestResponse( finding=item, burpRequestBase64=req_resp["req"], burpResponseBase64=req_resp["resp"], ) burp_rr.clean() burp_rr.save() if item.unsaved_request is not None and item.unsaved_response is not None: burp_rr = BurpRawRequestResponse( finding=item, burpRequestBase64=item.unsaved_request, burpResponseBase64=item.unsaved_response, ) burp_rr.clean() burp_rr.save() for endpoint in item.unsaved_endpoints: ep, created = Endpoint.objects.get_or_create( protocol=endpoint.protocol, host=endpoint.host, path=endpoint.path, query=endpoint.query, fragment=endpoint.fragment, product=t.engagement.product) item.endpoints.add(ep) item.save(false_history=True) if item.unsaved_tags is not None: item.tags = item.unsaved_tags finding_count += 1 messages.add_message( request, messages.SUCCESS, scan_type + ' processed, a total of ' + message( finding_count, 'finding', 'processed'), extra_tags='alert-success') create_notification( event='results_added', title=str(finding_count) + " findings for " + engagement.product.name, finding_count=finding_count, test=t, engagement=engagement, url=request.build_absolute_uri( reverse('view_test', args=(t.id, )))) return HttpResponseRedirect( reverse('view_test', args=(t.id, ))) except SyntaxError: messages.add_message( request, messages.ERROR, 'There appears to be an error in the XML report, please check and try again.', extra_tags='alert-danger') prod_id = None custom_breadcrumb = None title = "Import Scan Results" if engagement: prod_id = engagement.product.id product_tab = Product_Tab(prod_id, title=title, tab="engagements") product_tab.setEngagement(engagement) else: prod_id = pid custom_breadcrumb = {"", ""} product_tab = Product_Tab(prod_id, title=title, tab="findings") return render(request, 'dojo/import_scan_results.html', { 'form': form, 'product_tab': product_tab, 'custom_breadcrumb': custom_breadcrumb, 'title': title, 'cred_form': cred_form, })
def edit_engagement(request, eid): eng = Engagement.objects.get(pk=eid) ci_cd_form = False if eng.engagement_type == "CI/CD": ci_cd_form = True jform = None if request.method == 'POST': form = EngForm(request.POST, instance=eng, cicd=ci_cd_form, product=eng.product.id) if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm( request.POST, prefix='jiraform', enabled=True) if (form.is_valid() and jform is None) or (form.is_valid() and jform and jform.is_valid()): if 'jiraform-push_to_jira' in request.POST: if JIRA_Issue.objects.filter(engagement=eng).exists(): update_epic_task.delay( eng, jform.cleaned_data.get('push_to_jira')) enabled = True else: enabled = False add_epic_task.delay(eng, jform.cleaned_data.get('push_to_jira')) temp_form = form.save(commit=False) if (temp_form.status == "Cancelled" or temp_form.status == "Completed"): temp_form.active = False elif(temp_form.active is False): temp_form.active = True temp_form.save() tags = request.POST.getlist('tags') t = ", ".join(tags) eng.tags = t messages.add_message( request, messages.SUCCESS, 'Engagement updated successfully.', extra_tags='alert-success') if '_Add Tests' in request.POST: return HttpResponseRedirect( reverse('add_tests', args=(eng.id, ))) else: return HttpResponseRedirect( reverse('view_engagement', args=(eng.id, ))) else: form = EngForm(instance=eng, cicd=ci_cd_form, product=eng.product.id) try: # jissue = JIRA_Issue.objects.get(engagement=eng) enabled = True except: enabled = False pass if get_system_setting('enable_jira') and JIRA_PKey.objects.filter( product=eng.product).count() != 0: jform = JIRAFindingForm(prefix='jiraform', enabled=enabled) else: jform = None form.initial['tags'] = [tag.name for tag in eng.tags] title = "" if eng.engagement_type == "CI/CD": title = " CI/CD" product_tab = Product_Tab(eng.product.id, title="Edit" + title + " Engagement", tab="engagements") product_tab.setEngagement(eng) return render(request, 'dojo/new_eng.html', { 'product_tab': product_tab, 'form': form, 'edit': True, 'jform': jform, 'eng': eng })
def ad_hoc_finding(request, pid): prod = Product.objects.get(id=pid) test = None try: eng = Engagement.objects.get(product=prod, name="Ad Hoc Engagement") tests = Test.objects.filter(engagement=eng) if len(tests) != 0: test = tests[0] else: test = Test(engagement=eng, test_type=Test_Type.objects.get(name="Pen Test"), target_start=timezone.now(), target_end=timezone.now()) test.save() except: eng = Engagement(name="Ad Hoc Engagement", target_start=timezone.now(), target_end=timezone.now(), active=False, product=prod) eng.save() test = Test(engagement=eng, test_type=Test_Type.objects.get(name="Pen Test"), target_start=timezone.now(), target_end=timezone.now()) test.save() form_error = False enabled = False jform = None form = AdHocFindingForm(initial={'date': timezone.now().date()}) if get_system_setting('enable_jira'): if JIRA_PKey.objects.filter(product=test.engagement.product).count() != 0: enabled = JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues jform = JIRAFindingForm(enabled=enabled, prefix='jiraform') else: jform = None if request.method == 'POST': form = AdHocFindingForm(request.POST) if form.is_valid(): new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) if new_finding.false_p or new_finding.active is False: new_finding.mitigated = timezone.now() new_finding.mitigated_by = request.user create_template = new_finding.is_template # always false now since this will be deprecated soon in favor of new Finding_Template model new_finding.is_template = False new_finding.save() new_finding.endpoints = form.cleaned_data['endpoints'] new_finding.save() if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=enabled) if jform.is_valid(): add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira')) messages.add_message(request, messages.SUCCESS, 'Finding added successfully.', extra_tags='alert-success') if create_template: templates = Finding_Template.objects.filter(title=new_finding.title) if len(templates) > 0: messages.add_message(request, messages.ERROR, 'A finding template was not created. A template with this title already ' 'exists.', extra_tags='alert-danger') else: template = Finding_Template(title=new_finding.title, cwe=new_finding.cwe, severity=new_finding.severity, description=new_finding.description, mitigation=new_finding.mitigation, impact=new_finding.impact, references=new_finding.references, numerical_severity=new_finding.numerical_severity) template.save() messages.add_message(request, messages.SUCCESS, 'A finding template was also created.', extra_tags='alert-success') if '_Finished' in request.POST: return HttpResponseRedirect(reverse('view_test', args=(test.id,))) else: return HttpResponseRedirect(reverse('add_findings', args=(test.id,))) else: if 'endpoints' in form.cleaned_data: form.fields['endpoints'].queryset = form.cleaned_data['endpoints'] else: form.fields['endpoints'].queryset = Endpoint.objects.none() form_error = True messages.add_message(request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') product_tab = Product_Tab(pid, title="Add Finding", tab="engagements") product_tab.setEngagement(eng) return render(request, 'dojo/ad_hoc_findings.html', {'form': form, 'product_tab': product_tab, 'temp': False, 'tid': test.id, 'pid': pid, 'form_error': form_error, 'jform': jform, })
def add_tests(request, eid): eng = Engagement.objects.get(id=eid) cred_form = CredMappingForm() cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter( engagement=eng).order_by('cred_id') if request.method == 'POST': form = TestForm(request.POST) cred_form = CredMappingForm(request.POST) cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter( engagement=eng).order_by('cred_id') if form.is_valid(): new_test = form.save(commit=False) new_test.engagement = eng try: new_test.lead = User.objects.get(id=form['lead'].value()) except: new_test.lead = None pass # Set status to in progress if a test is added if eng.status != "In Progress" and eng.active is True: eng.status = "In Progress" eng.save() new_test.save() tags = request.POST.getlist('tags') t = ", ".join(tags) new_test.tags = t # Save the credential to the test if cred_form.is_valid(): if cred_form.cleaned_data['cred_user']: # Select the credential mapping object from the selected list and only allow if the credential is associated with the product cred_user = Cred_Mapping.objects.filter( pk=cred_form.cleaned_data['cred_user'].id, engagement=eid).first() new_f = cred_form.save(commit=False) new_f.test = new_test new_f.cred_id = cred_user.cred_id new_f.save() messages.add_message( request, messages.SUCCESS, 'Test added successfully.', extra_tags='alert-success') create_notification( event='test_added', title=new_test.test_type.name + " for " + eng.product.name, test=new_test, engagement=eng, url=request.build_absolute_uri( reverse('view_engagement', args=(eng.id, )))) if '_Add Another Test' in request.POST: return HttpResponseRedirect( reverse('add_tests', args=(eng.id, ))) elif '_Add Findings' in request.POST: return HttpResponseRedirect( reverse('add_findings', args=(new_test.id, ))) elif '_Finished' in request.POST: return HttpResponseRedirect( reverse('view_engagement', args=(eng.id, ))) else: form = TestForm() form.initial['target_start'] = eng.target_start form.initial['target_end'] = eng.target_end form.initial['lead'] = request.user add_breadcrumb( parent=eng, title="Add Tests", top_level=False, request=request) product_tab = Product_Tab(eng.product.id, title="Add Tests", tab="engagements") product_tab.setEngagement(eng) return render(request, 'dojo/add_tests.html', { 'product_tab': product_tab, 'form': form, 'cred_form': cred_form, 'eid': eid, 'eng': eng })
def re_import_scan_results(request, tid): additional_message = "When re-uploading a scan, any findings not found in original scan will be updated as " \ "mitigated. The process attempts to identify the differences, however manual verification " \ "is highly recommended." test = get_object_or_404(Test, id=tid) # by default we keep a trace of the scan_type used to create the test # if it's not here, we use the "name" of the test type # this feature exists to provide custom label for tests for some parsers if test.scan_type: scan_type = test.scan_type else: scan_type = test.test_type.name engagement = test.engagement form = ReImportScanForm(test=test) jform = None jira_project = jira_helper.get_jira_project(test) push_all_jira_issues = jira_helper.is_push_all_issues(test) # Decide if we need to present the Push to JIRA form if get_system_setting('enable_jira') and jira_project: jform = JIRAImportScanForm(push_all=push_all_jira_issues, prefix='jiraform') if request.method == "POST": form = ReImportScanForm(request.POST, request.FILES, test=test) if jira_project: jform = JIRAImportScanForm(request.POST, push_all=push_all_jira_issues, prefix='jiraform') if form.is_valid() and (jform is None or jform.is_valid()): scan_date = form.cleaned_data['scan_date'] minimum_severity = form.cleaned_data['minimum_severity'] scan = request.FILES.get('file', None) active = form.cleaned_data['active'] verified = form.cleaned_data['verified'] tags = form.cleaned_data['tags'] version = form.cleaned_data.get('version', None) branch_tag = form.cleaned_data.get('branch_tag', None) build_id = form.cleaned_data.get('build_id', None) commit_hash = form.cleaned_data.get('commit_hash', None) api_scan_configuration = form.cleaned_data.get( 'api_scan_configuration', None) service = form.cleaned_data.get('service', None) endpoints_to_add = None # not available on reimport UI close_old_findings = form.cleaned_data.get('close_old_findings', True) group_by = form.cleaned_data.get('group_by', None) # Tags are replaced, same behaviour as with django-tagging test.tags = tags test.version = version if scan and is_scan_file_too_large(scan): messages.add_message( request, messages.ERROR, "Report file is too large. Maximum supported size is {} MB" .format(settings.SCAN_FILE_MAX_SIZE), extra_tags='alert-danger') return HttpResponseRedirect( reverse('re_import_scan_results', args=(test.id, ))) push_to_jira = push_all_jira_issues or ( jform and jform.cleaned_data.get('push_to_jira')) error = False finding_count, new_finding_count, closed_finding_count, reactivated_finding_count, untouched_finding_count = 0, 0, 0, 0, 0 reimporter = ReImporter() try: test, finding_count, new_finding_count, closed_finding_count, reactivated_finding_count, untouched_finding_count, _ = \ reimporter.reimport_scan(scan, scan_type, test, active=active, verified=verified, tags=None, minimum_severity=minimum_severity, endpoints_to_add=endpoints_to_add, scan_date=scan_date, version=version, branch_tag=branch_tag, build_id=build_id, commit_hash=commit_hash, push_to_jira=push_to_jira, close_old_findings=close_old_findings, group_by=group_by, api_scan_configuration=api_scan_configuration, service=service) except Exception as e: logger.exception(e) add_error_message_to_response( 'An exception error occurred during the report import:%s' % str(e)) error = True if not error: message = construct_imported_message( scan_type, finding_count, new_finding_count=new_finding_count, closed_finding_count=closed_finding_count, reactivated_finding_count=reactivated_finding_count, untouched_finding_count=untouched_finding_count) add_success_message_to_response(message) return HttpResponseRedirect(reverse('view_test', args=(test.id, ))) product_tab = Product_Tab(engagement.product.id, title="Re-upload a %s" % scan_type, tab="engagements") product_tab.setEngagement(engagement) form.fields['endpoints'].queryset = Endpoint.objects.filter( product__id=product_tab.product.id) form.initial['api_scan_configuration'] = test.api_scan_configuration form.fields[ 'api_scan_configuration'].queryset = Product_API_Scan_Configuration.objects.filter( product__id=product_tab.product.id) return render( request, 'dojo/import_scan_results.html', { 'form': form, 'product_tab': product_tab, 'eid': engagement.id, 'additional_message': additional_message, 'jform': jform, 'scan_types': get_scan_types_sorted(), })
def edit_engagement(request, eid): engagement = Engagement.objects.get(pk=eid) is_ci_cd = engagement.engagement_type == "CI/CD" jira_project_form = None jira_epic_form = None jira_project = None jira_error = False if request.method == 'POST': form = EngForm(request.POST, instance=engagement, cicd=is_ci_cd, product=engagement.product, user=request.user) jira_project = jira_helper.get_jira_project(engagement, use_inheritance=False) if form.is_valid(): # first save engagement details new_status = form.cleaned_data.get('status') engagement = form.save(commit=False) if (new_status == "Cancelled" or new_status == "Completed"): engagement.active = False create_notification(event='close_engagement', title='Closure of %s' % engagement.name, description='The engagement "%s" was closed' % (engagement.name), engagement=engagement, url=reverse('engagement_all_findings', args=(engagement.id, ))), else: engagement.active = True engagement.save() form.save_m2m() messages.add_message( request, messages.SUCCESS, 'Engagement updated successfully.', extra_tags='alert-success') success, jira_project_form = jira_helper.process_jira_project_form(request, instance=jira_project, target='engagement', engagement=engagement, product=engagement.product) error = not success success, jira_epic_form = jira_helper.process_jira_epic_form(request, engagement=engagement) error = error or not success if not error: if '_Add Tests' in request.POST: return HttpResponseRedirect( reverse('add_tests', args=(engagement.id, ))) else: return HttpResponseRedirect( reverse('view_engagement', args=(engagement.id, ))) else: logger.debug(form.errors) else: form = EngForm(initial={'product': engagement.product}, instance=engagement, cicd=is_ci_cd, product=engagement.product, user=request.user) jira_epic_form = None if get_system_setting('enable_jira'): jira_project = jira_helper.get_jira_project(engagement, use_inheritance=False) jira_project_form = JIRAProjectForm(instance=jira_project, target='engagement', product=engagement.product) logger.debug('showing jira-epic-form') jira_epic_form = JIRAEngagementForm(instance=engagement) if is_ci_cd: title = 'Edit CI/CD Engagement' else: title = 'Edit Interactive Engagement' product_tab = Product_Tab(engagement.product.id, title=title, tab="engagements") product_tab.setEngagement(engagement) return render(request, 'dojo/new_eng.html', { 'product_tab': product_tab, 'title': title, 'form': form, 'edit': True, 'jira_epic_form': jira_epic_form, 'jira_project_form': jira_project_form, 'engagement': engagement, })
def generate_report(request, obj): user = Dojo_User.objects.get(id=request.user.id) product_type = None product = None engagement = None test = None endpoint = None endpoints = None endpoint_all_findings = None endpoint_monthly_counts = None endpoint_active_findings = None accepted_findings = None open_findings = None closed_findings = None verified_findings = None report_title = None report_subtitle = None report_info = "Generated By %s on %s" % (user.get_full_name(), ( timezone.now().strftime("%m/%d/%Y %I:%M%p %Z"))) if type(obj).__name__ == "Product": if request.user.is_staff or check_auth_users_list(request.user, obj): pass # user is authorized for this product else: raise PermissionDenied elif type(obj).__name__ == "Endpoint": if request.user.is_staff or check_auth_users_list(request.user, obj): pass # user is authorized for this product else: raise PermissionDenied elif type(obj).__name__ == "QuerySet" or type( obj).__name__ == "CastTaggedQuerySet": # authorization taken care of by only selecting findings from product user is authed to see pass else: if not request.user.is_staff: raise PermissionDenied report_format = request.GET.get('report_type', 'AsciiDoc') include_finding_notes = int(request.GET.get('include_finding_notes', 0)) include_finding_images = int(request.GET.get('include_finding_images', 0)) include_executive_summary = int( request.GET.get('include_executive_summary', 0)) include_table_of_contents = int( request.GET.get('include_table_of_contents', 0)) generate = "_generate" in request.GET report_name = str(obj) report_type = type(obj).__name__ add_breadcrumb(title="Generate Report", top_level=False, request=request) if type(obj).__name__ == "Product_Type": product_type = obj filename = "product_type_finding_report.pdf" template = "dojo/product_type_pdf_report.html" report_name = "Product Type Report: " + str(product_type) report_title = "Product Type Report" report_subtitle = str(product_type) findings = ReportFindingFilter( request.GET, prod_type=product_type, queryset=prefetch_related_findings_for_report( Finding.objects.filter( test__engagement__product__prod_type=product_type))) products = Product.objects.filter( prod_type=product_type, engagement__test__finding__in=findings.qs).distinct() engagements = Engagement.objects.filter( product__prod_type=product_type, test__finding__in=findings.qs).distinct() tests = Test.objects.filter( engagement__product__prod_type=product_type, finding__in=findings.qs).distinct() if len(findings.qs) > 0: start_date = timezone.make_aware( datetime.combine(findings.qs.last().date, datetime.min.time())) else: start_date = timezone.now() end_date = timezone.now() r = relativedelta(end_date, start_date) months_between = (r.years * 12) + r.months # include current month months_between += 1 endpoint_monthly_counts = get_period_counts_legacy( findings.qs.order_by('numerical_severity'), findings.qs.order_by('numerical_severity'), None, months_between, start_date, relative_delta='months') context = { 'product_type': product_type, 'products': products, 'engagements': engagements, 'tests': tests, 'report_name': report_name, 'endpoint_opened_per_month': endpoint_monthly_counts['opened_per_period'] if endpoint_monthly_counts is not None else [], 'endpoint_active_findings': findings.qs.order_by('numerical_severity'), 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': report_title, 'host': report_url_resolver(request), 'user_id': request.user.id } elif type(obj).__name__ == "Product": product = obj filename = "product_finding_report.pdf" template = "dojo/product_pdf_report.html" report_name = "Product Report: " + str(product) report_title = "Product Report" report_subtitle = str(product) findings = ReportFindingFilter( request.GET, product=product, queryset=prefetch_related_findings_for_report( Finding.objects.filter(test__engagement__product=product))) ids = set(finding.id for finding in findings.qs) engagements = Engagement.objects.filter( test__finding__id__in=ids).distinct() tests = Test.objects.filter(finding__id__in=ids).distinct() ids = get_endpoint_ids( Endpoint.objects.filter(product=product).distinct()) endpoints = Endpoint.objects.filter(id__in=ids) context = { 'product': product, 'engagements': engagements, 'tests': tests, 'report_name': report_name, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': report_title, 'endpoints': endpoints, 'host': report_url_resolver(request), 'user_id': request.user.id } elif type(obj).__name__ == "Engagement": logger.debug('generating report for Engagement') engagement = obj findings = ReportFindingFilter( request.GET, engagement=engagement, queryset=prefetch_related_findings_for_report( Finding.objects.filter(test__engagement=engagement))) report_name = "Engagement Report: " + str(engagement) filename = "engagement_finding_report.pdf" template = 'dojo/engagement_pdf_report.html' report_title = "Engagement Report" report_subtitle = str(engagement) ids = set(finding.id for finding in findings.qs) tests = Test.objects.filter(finding__id__in=ids).distinct() ids = get_endpoint_ids( Endpoint.objects.filter(product=engagement.product).distinct()) endpoints = Endpoint.objects.filter(id__in=ids) context = { 'engagement': engagement, 'tests': tests, 'report_name': report_name, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': report_title, 'host': report_url_resolver(request), 'user_id': request.user.id, 'endpoints': endpoints } elif type(obj).__name__ == "Test": test = obj findings = ReportFindingFilter( request.GET, engagement=test.engagement, queryset=prefetch_related_findings_for_report( Finding.objects.filter(test=test))) filename = "test_finding_report.pdf" template = "dojo/test_pdf_report.html" report_name = "Test Report: " + str(test) report_title = "Test Report" report_subtitle = str(test) context = { 'test': test, 'report_name': report_name, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': report_title, 'host': report_url_resolver(request), 'user_id': request.user.id } elif type(obj).__name__ == "Endpoint": endpoint = obj host = endpoint.host_no_port report_name = "Endpoint Report: " + host report_type = "Endpoint" endpoints = Endpoint.objects.filter( host__regex="^" + host + ":?", product=endpoint.product).distinct() filename = "endpoint_finding_report.pdf" template = 'dojo/endpoint_pdf_report.html' report_title = "Endpoint Report" report_subtitle = host findings = ReportFindingFilter( request.GET, queryset=prefetch_related_findings_for_report( Finding.objects.filter(endpoints__in=endpoints))) context = { 'endpoint': endpoint, 'endpoints': endpoints, 'report_name': report_name, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': get_system_setting('team_name'), 'title': report_title, 'host': report_url_resolver(request), 'user_id': request.user.id } elif type(obj).__name__ == "QuerySet" or type( obj).__name__ == "CastTaggedQuerySet": findings = ReportAuthedFindingFilter( request.GET, queryset=prefetch_related_findings_for_report(obj).distinct()) filename = "finding_report.pdf" report_name = 'Finding' report_type = 'Finding' template = 'dojo/finding_pdf_report.html' report_title = "Finding Report" report_subtitle = '' context = { 'findings': findings.qs.order_by('numerical_severity'), 'report_name': report_name, 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': report_title, 'host': report_url_resolver(request), 'user_id': request.user.id } else: raise Http404() report_form = ReportOptionsForm() if generate: report_form = ReportOptionsForm(request.GET) if report_format == 'AsciiDoc': return render( request, 'dojo/asciidoc_report.html', { 'product_type': product_type, 'product': product, 'engagement': engagement, 'test': test, 'endpoint': endpoint, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': report_title, 'user_id': request.user.id, 'host': report_url_resolver(request), 'context': context, }) elif report_format == 'PDF': if 'regen' in request.GET: # we should already have a report object, lets get and use it report = get_object_or_404(Report, id=request.GET['regen']) report.datetime = timezone.now() report.status = 'requested' if report.requester.username != request.user.username: report.requester = request.user else: # lets create the report object and send it in to celery task report = Report(name=report_name, type=report_type, format='PDF', requester=request.user, task_id='tbd', options=request.path + "?" + request.GET.urlencode()) report.save() async_pdf_report.delay(report=report, template=template, filename=filename, report_title=report_title, report_subtitle=report_subtitle, report_info=report_info, context=context, uri=request.build_absolute_uri( report.get_url())) messages.add_message(request, messages.SUCCESS, 'Your report is building.', extra_tags='alert-success') return HttpResponseRedirect(reverse('reports')) elif report_format == 'HTML': return render( request, template, { 'product_type': product_type, 'product': product, 'engagement': engagement, 'report_name': report_name, 'test': test, 'endpoint': endpoint, 'endpoints': endpoints, 'findings': findings.qs.order_by('numerical_severity'), 'include_finding_notes': include_finding_notes, 'include_finding_images': include_finding_images, 'include_executive_summary': include_executive_summary, 'include_table_of_contents': include_table_of_contents, 'user': user, 'team_name': settings.TEAM_NAME, 'title': report_title, 'user_id': request.user.id, 'host': "", 'context': context, }) else: raise Http404() paged_findings = get_page_items(request, findings.qs.order_by('numerical_severity'), 25) product_tab = None if engagement: product_tab = Product_Tab(engagement.product.id, title="Engagement Report", tab="engagements") product_tab.setEngagement(engagement) elif test: product_tab = Product_Tab(test.engagement.product.id, title="Test Report", tab="engagements") product_tab.setEngagement(test.engagement) elif product: product_tab = Product_Tab(product.id, title="Product Report", tab="findings") elif endpoints: product_tab = Product_Tab(endpoint.product.id, title="Endpoint Report", tab="endpoints") return render( request, 'dojo/request_report.html', { 'product_type': product_type, 'product': product, 'product_tab': product_tab, 'engagement': engagement, 'test': test, 'endpoint': endpoint, 'findings': findings, 'paged_findings': paged_findings, 'report_form': report_form, 'context': context, })
def add_tests(request, eid): eng = Engagement.objects.get(id=eid) cred_form = CredMappingForm() cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter( engagement=eng).order_by('cred_id') if request.method == 'POST': form = TestForm(request.POST, engagement=eng) cred_form = CredMappingForm(request.POST) cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter( engagement=eng).order_by('cred_id') if form.is_valid(): new_test = form.save(commit=False) # set default scan_type as it's used in reimport new_test.scan_type = new_test.test_type.name new_test.engagement = eng try: new_test.lead = User.objects.get(id=form['lead'].value()) except: new_test.lead = None pass # Set status to in progress if a test is added if eng.status != "In Progress" and eng.active is True: eng.status = "In Progress" eng.save() new_test.save() # Save the credential to the test if cred_form.is_valid(): if cred_form.cleaned_data['cred_user']: # Select the credential mapping object from the selected list and only allow if the credential is associated with the product cred_user = Cred_Mapping.objects.filter( pk=cred_form.cleaned_data['cred_user'].id, engagement=eid).first() new_f = cred_form.save(commit=False) new_f.test = new_test new_f.cred_id = cred_user.cred_id new_f.save() messages.add_message( request, messages.SUCCESS, 'Test added successfully.', extra_tags='alert-success') notifications_helper.notify_test_created(new_test) if '_Add Another Test' in request.POST: return HttpResponseRedirect( reverse('add_tests', args=(eng.id, ))) elif '_Add Findings' in request.POST: return HttpResponseRedirect( reverse('add_findings', args=(new_test.id, ))) elif '_Finished' in request.POST: return HttpResponseRedirect( reverse('view_engagement', args=(eng.id, ))) else: form = TestForm(engagement=eng) form.initial['target_start'] = eng.target_start form.initial['target_end'] = eng.target_end form.initial['lead'] = request.user add_breadcrumb( parent=eng, title="Add Tests", top_level=False, request=request) product_tab = Product_Tab(eng.product.id, title="Add Tests", tab="engagements") product_tab.setEngagement(eng) return render(request, 'dojo/add_tests.html', { 'product_tab': product_tab, 'form': form, 'cred_form': cred_form, 'eid': eid, 'eng': eng })
def view_test(request, tid): test = get_object_or_404(Test, pk=tid) prod = test.engagement.product tags = Tag.objects.usage_for_model(Finding) notes = test.notes.all() note_type_activation = Note_Type.objects.filter(is_active=True).count() if note_type_activation: available_note_types = find_available_notetypes(notes) person = request.user.username findings = Finding.objects.filter(test=test).order_by('numerical_severity') findings = OpenFindingFilter(request.GET, queryset=findings) stub_findings = Stub_Finding.objects.filter(test=test) cred_test = Cred_Mapping.objects.filter( test=test).select_related('cred_id').order_by('cred_id') creds = Cred_Mapping.objects.filter( engagement=test.engagement).select_related('cred_id').order_by( 'cred_id') system_settings = get_object_or_404(System_Settings, id=1) if request.method == 'POST' and request.user.is_staff: if note_type_activation: form = TypedNoteForm(request.POST, available_note_types=available_note_types) else: form = NoteForm(request.POST) if form.is_valid(): new_note = form.save(commit=False) new_note.author = request.user new_note.date = timezone.now() new_note.save() test.notes.add(new_note) if note_type_activation: form = TypedNoteForm(available_note_types=available_note_types) else: form = NoteForm() url = request.build_absolute_uri( reverse("view_test", args=(test.id, ))) title = "Test: %s on %s" % (test.test_type.name, test.engagement.product.name) process_notifications(request, new_note, url, title) messages.add_message(request, messages.SUCCESS, 'Note added successfully.', extra_tags='alert-success') else: if note_type_activation: form = TypedNoteForm(available_note_types=available_note_types) else: form = NoteForm() title_words = get_words_for_field(findings.qs, 'title') component_words = get_words_for_field(findings.qs, 'component_name') paged_findings, total_findings_count = get_page_items_and_count( request, prefetch_for_findings(findings.qs), 25) paged_stub_findings = get_page_items(request, stub_findings, 25) show_re_upload = any(test.test_type.name in code for code in ImportScanForm.SCAN_TYPE_CHOICES) product_tab = Product_Tab(prod.id, title="Test", tab="engagements") product_tab.setEngagement(test.engagement) jira_config = JIRA_PKey.objects.filter(product=prod.id).first() if jira_config: jira_config = jira_config.conf_id google_sheets_enabled = system_settings.enable_google_sheets sheet_url = None if google_sheets_enabled: spreadsheet_name = test.engagement.product.name + "-" + test.engagement.name + "-" + str( test.id) system_settings = get_object_or_404(System_Settings, id=1) service_account_info = json.loads(system_settings.credentials) SCOPES = ['https://www.googleapis.com/auth/drive'] credentials = service_account.Credentials.from_service_account_info( service_account_info, scopes=SCOPES) try: drive_service = googleapiclient.discovery.build( 'drive', 'v3', credentials=credentials, cache_discovery=False) folder_id = system_settings.drive_folder_ID files = drive_service.files().list( q="mimeType='application/vnd.google-apps.spreadsheet' and parents in '%s' and name='%s'" % (folder_id, spreadsheet_name), spaces='drive', pageSize=10, fields='files(id, name)').execute() except googleapiclient.errors.HttpError: messages.add_message( request, messages.ERROR, "There is a problem with the Google Sheets Sync Configuration. Contact your system admin to solve the issue. Until fixed Google Shet Sync feature can not be used.", extra_tags="alert-danger", ) google_sheets_enabled = False except httplib2.ServerNotFoundError: messages.add_message( request, messages.ERROR, "Unable to reach the Google Sheet API.", extra_tags="alert-danger", ) else: spreadsheets = files.get('files') if len(spreadsheets) == 1: spreadsheetId = spreadsheets[0].get('id') sheet_url = 'https://docs.google.com/spreadsheets/d/' + spreadsheetId return render( request, 'dojo/view_test.html', { 'test': test, 'product_tab': product_tab, 'findings': paged_findings, 'filtered': findings, 'findings_count': total_findings_count, 'stub_findings': paged_stub_findings, 'title_words': title_words, 'component_words': component_words, 'form': form, 'notes': notes, 'person': person, 'request': request, 'show_re_upload': show_re_upload, 'creds': creds, 'cred_test': cred_test, 'tag_input': tags, 'jira_config': jira_config, 'show_export': google_sheets_enabled, 'sheet_url': sheet_url })
def re_import_scan_results(request, tid): additional_message = "When re-uploading a scan, any findings not found in original scan will be updated as " \ "mitigated. The process attempts to identify the differences, however manual verification " \ "is highly recommended." t = get_object_or_404(Test, id=tid) scan_type = t.test_type.name engagement = t.engagement form = ReImportScanForm() form.initial['tags'] = [tag.name for tag in t.tags] if request.method == "POST": form = ReImportScanForm(request.POST, request.FILES) if form.is_valid(): scan_date = form.cleaned_data['scan_date'] min_sev = form.cleaned_data['minimum_severity'] file = request.FILES['file'] scan_type = t.test_type.name active = form.cleaned_data['active'] verified = form.cleaned_data['verified'] tags = request.POST.getlist('tags') ts = ", ".join(tags) t.tags = ts try: parser = import_parser_factory(file, t) except ValueError: raise Http404() try: items = parser.items original_items = t.finding_set.all().values_list("id", flat=True) new_items = [] mitigated_count = 0 finding_count = 0 finding_added_count = 0 reactivated_count = 0 for item in items: sev = item.severity if sev == 'Information' or sev == 'Informational': sev = 'Info' item.severity = sev if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]: continue if scan_type == 'Veracode Scan' or scan_type == 'Arachni Scan': find = Finding.objects.filter(title=item.title, test__id=t.id, severity=sev, numerical_severity=Finding.get_numerical_severity(sev), description=item.description ) else: find = Finding.objects.filter(title=item.title, test__id=t.id, severity=sev, numerical_severity=Finding.get_numerical_severity(sev), ) if len(find) == 1: find = find[0] if find.mitigated: # it was once fixed, but now back find.mitigated = None find.mitigated_by = None find.active = True find.verified = verified find.save() note = Notes(entry="Re-activated by %s re-upload." % scan_type, author=request.user) note.save() find.notes.add(note) reactivated_count += 1 new_items.append(find.id) else: item.test = t item.date = t.target_start item.reporter = request.user item.last_reviewed = timezone.now() item.last_reviewed_by = request.user item.verified = verified item.active = active item.save() finding_added_count += 1 new_items.append(item.id) find = item if hasattr(item, 'unsaved_req_resp') and len(item.unsaved_req_resp) > 0: for req_resp in item.unsaved_req_resp: burp_rr = BurpRawRequestResponse(finding=find, burpRequestBase64=req_resp["req"], burpResponseBase64=req_resp["resp"], ) burp_rr.clean() burp_rr.save() if item.unsaved_request is not None and item.unsaved_response is not None: burp_rr = BurpRawRequestResponse(finding=find, burpRequestBase64=item.unsaved_request, burpResponseBase64=item.unsaved_response, ) burp_rr.clean() burp_rr.save() if find: finding_count += 1 for endpoint in item.unsaved_endpoints: ep, created = Endpoint.objects.get_or_create(protocol=endpoint.protocol, host=endpoint.host, path=endpoint.path, query=endpoint.query, fragment=endpoint.fragment, product=t.engagement.product) find.endpoints.add(ep) if item.unsaved_tags is not None: find.tags = item.unsaved_tags # calculate the difference to_mitigate = set(original_items) - set(new_items) for finding_id in to_mitigate: finding = Finding.objects.get(id=finding_id) finding.mitigated = datetime.combine(scan_date, timezone.now().time()) finding.mitigated_by = request.user finding.active = False finding.save() note = Notes(entry="Mitigated by %s re-upload." % scan_type, author=request.user) note.save() finding.notes.add(note) mitigated_count += 1 messages.add_message(request, messages.SUCCESS, '%s processed, a total of ' % scan_type + message(finding_count, 'finding', 'processed'), extra_tags='alert-success') if finding_added_count > 0: messages.add_message(request, messages.SUCCESS, 'A total of ' + message(finding_added_count, 'finding', 'added') + ', that are new to scan.', extra_tags='alert-success') if reactivated_count > 0: messages.add_message(request, messages.SUCCESS, 'A total of ' + message(reactivated_count, 'finding', 'reactivated') + ', that are back in scan results.', extra_tags='alert-success') if mitigated_count > 0: messages.add_message(request, messages.SUCCESS, 'A total of ' + message(mitigated_count, 'finding', 'mitigated') + '. Please manually verify each one.', extra_tags='alert-success') create_notification(event='results_added', title=str(finding_count) + " findings for " + engagement.product.name, finding_count=finding_count, test=t, engagement=engagement, url=request.build_absolute_uri(reverse('view_test', args=(t.id,)))) return HttpResponseRedirect(reverse('view_test', args=(t.id,))) except SyntaxError: messages.add_message(request, messages.ERROR, 'There appears to be an error in the XML report, please check and try again.', extra_tags='alert-danger') product_tab = Product_Tab(engagement.product.id, title="Re-upload a %s" % scan_type, tab="engagements") product_tab.setEngagement(engagement) return render(request, 'dojo/import_scan_results.html', {'form': form, 'product_tab': product_tab, 'eid': engagement.id, 'additional_message': additional_message, })
def view_engagement(request, eid): eng = get_object_or_404(Engagement, id=eid) tests = eng.test_set.all().order_by('test_type__name', '-updated') default_page_num = 10 tests_filter = EngagementTestFilter(request.GET, queryset=tests, engagement=eng) paged_tests = get_page_items(request, tests_filter.qs, default_page_num) # prefetch only after creating the filters to avoid https://code.djangoproject.com/ticket/23771 and https://code.djangoproject.com/ticket/25375 paged_tests.object_list = prefetch_for_view_tests(paged_tests.object_list) prod = eng.product risks_accepted = eng.risk_acceptance.all().select_related('owner').annotate(accepted_findings_count=Count('accepted_findings__id')) preset_test_type = None network = None if eng.preset: preset_test_type = eng.preset.test_type.all() network = eng.preset.network_locations.all() system_settings = System_Settings.objects.get() jissue = jira_helper.get_jira_issue(eng) jira_project = jira_helper.get_jira_project(eng) try: check = Check_List.objects.get(engagement=eng) except: check = None pass notes = eng.notes.all() note_type_activation = Note_Type.objects.filter(is_active=True).count() if note_type_activation: available_note_types = find_available_notetypes(notes) form = DoneForm() files = eng.files.all() if request.method == 'POST': user_has_permission_or_403(request.user, eng, Permissions.Note_Add) eng.progress = 'check_list' eng.save() if note_type_activation: form = TypedNoteForm(request.POST, available_note_types=available_note_types) else: form = NoteForm(request.POST) if form.is_valid(): new_note = form.save(commit=False) new_note.author = request.user new_note.date = timezone.now() new_note.save() eng.notes.add(new_note) if note_type_activation: form = TypedNoteForm(available_note_types=available_note_types) else: form = NoteForm() url = request.build_absolute_uri(reverse("view_engagement", args=(eng.id,))) title = "Engagement: %s on %s" % (eng.name, eng.product.name) messages.add_message(request, messages.SUCCESS, 'Note added successfully.', extra_tags='alert-success') else: if note_type_activation: form = TypedNoteForm(available_note_types=available_note_types) else: form = NoteForm() creds = Cred_Mapping.objects.filter( product=eng.product).select_related('cred_id').order_by('cred_id') cred_eng = Cred_Mapping.objects.filter( engagement=eng.id).select_related('cred_id').order_by('cred_id') add_breadcrumb(parent=eng, top_level=False, request=request) title = "" if eng.engagement_type == "CI/CD": title = " CI/CD" product_tab = Product_Tab(prod.id, title="View" + title + " Engagement", tab="engagements") product_tab.setEngagement(eng) return render( request, 'dojo/view_eng.html', { 'eng': eng, 'product_tab': product_tab, 'system_settings': system_settings, 'tests': paged_tests, 'filter': tests_filter, 'check': check, 'threat': eng.tmodel_path, 'form': form, 'notes': notes, 'files': files, 'risks_accepted': risks_accepted, 'jissue': jissue, 'jira_project': jira_project, 'creds': creds, 'cred_eng': cred_eng, 'network': network, 'preset_test_type': preset_test_type })
def view_risk(request, eid, raid): risk_approval = get_object_or_404(Risk_Acceptance, pk=raid) eng = get_object_or_404(Engagement, pk=eid) if (request.user.is_staff or request.user in eng.product.authorized_users.all()): pass else: raise PermissionDenied a_file = risk_approval.path if request.method == 'POST': note_form = NoteForm(request.POST) if note_form.is_valid(): new_note = note_form.save(commit=False) new_note.author = request.user new_note.date = timezone.now() new_note.save() risk_approval.notes.add(new_note) messages.add_message( request, messages.SUCCESS, 'Note added successfully.', extra_tags='alert-success') if 'delete_note' in request.POST: note = get_object_or_404(Notes, pk=request.POST['delete_note_id']) if note.author.username == request.user.username: risk_approval.notes.remove(note) note.delete() messages.add_message( request, messages.SUCCESS, 'Note deleted successfully.', extra_tags='alert-success') else: messages.add_message( request, messages.ERROR, "Since you are not the note's author, it was not deleted.", extra_tags='alert-danger') if 'remove_finding' in request.POST: finding = get_object_or_404( Finding, pk=request.POST['remove_finding_id']) risk_approval.accepted_findings.remove(finding) finding.active = True finding.save() messages.add_message( request, messages.SUCCESS, 'Finding removed successfully.', extra_tags='alert-success') if 'replace_file' in request.POST: replace_form = ReplaceRiskAcceptanceForm( request.POST, request.FILES, instance=risk_approval) if replace_form.is_valid(): risk_approval.path.delete(save=False) risk_approval.path = replace_form.cleaned_data['path'] risk_approval.save() messages.add_message( request, messages.SUCCESS, 'File replaced successfully.', extra_tags='alert-success') if 'add_findings' in request.POST: add_findings_form = AddFindingsRiskAcceptanceForm( request.POST, request.FILES, instance=risk_approval) if add_findings_form.is_valid(): findings = add_findings_form.cleaned_data['accepted_findings'] for finding in findings: finding.active = False finding.save() risk_approval.accepted_findings.add(finding) risk_approval.save() messages.add_message( request, messages.SUCCESS, 'Finding%s added successfully.' % ('s' if len(findings) > 1 else ''), extra_tags='alert-success') note_form = NoteForm() replace_form = ReplaceRiskAcceptanceForm() add_findings_form = AddFindingsRiskAcceptanceForm() exclude_findings = [ finding.id for ra in eng.risk_acceptance.all() for finding in ra.accepted_findings.all() ] findings = Finding.objects.filter(test__in=eng.test_set.all()) \ .exclude(id__in=exclude_findings).order_by("title") add_fpage = get_page_items(request, findings, 10, 'apage') add_findings_form.fields[ "accepted_findings"].queryset = add_fpage.object_list fpage = get_page_items( request, risk_approval.accepted_findings.order_by('numerical_severity'), 15) authorized = (request.user == risk_approval.reporter.username or request.user.is_staff) product_tab = Product_Tab(eng.product.id, title="Risk Exception", tab="engagements") product_tab.setEngagement(eng) return render( request, 'dojo/view_risk.html', { 'risk_approval': risk_approval, 'product_tab': product_tab, 'accepted_findings': fpage, 'notes': risk_approval.notes.all(), 'a_file': a_file, 'eng': eng, 'note_form': note_form, 'replace_form': replace_form, 'add_findings_form': add_findings_form, 'show_add_findings_form': len(findings), 'request': request, 'add_findings': add_fpage, 'authorized': authorized, })
def import_scan_results(request, eid=None, pid=None): engagement = None form = ImportScanForm() cred_form = CredMappingForm() finding_count = 0 jform = None user = request.user if eid: engagement = get_object_or_404(Engagement, id=eid) engagement_or_product = engagement cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(engagement=engagement).order_by('cred_id') elif pid: product = get_object_or_404(Product, id=pid) engagement_or_product = product elif not user.is_staff: raise PermissionDenied user_has_permission_or_403(user, engagement_or_product, Permissions.Import_Scan_Result) push_all_jira_issues = jira_helper.is_push_all_issues(engagement_or_product) if request.method == "POST": form = ImportScanForm(request.POST, request.FILES) cred_form = CredMappingForm(request.POST) cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter( engagement=engagement).order_by('cred_id') if jira_helper.get_jira_project(engagement_or_product): jform = JIRAImportScanForm(request.POST, push_all=push_all_jira_issues, prefix='jiraform') logger.debug('jform valid: %s', jform.is_valid()) logger.debug('jform errors: %s', jform.errors) if form.is_valid() and (jform is None or jform.is_valid()): scan = request.FILES.get('file', None) scan_date = form.cleaned_data['scan_date'] minimum_severity = form.cleaned_data['minimum_severity'] active = form.cleaned_data['active'] verified = form.cleaned_data['verified'] scan_type = request.POST['scan_type'] tags = form.cleaned_data['tags'] version = form.cleaned_data['version'] branch_tag = form.cleaned_data.get('branch_tag', None) build_id = form.cleaned_data.get('build_id', None) commit_hash = form.cleaned_data.get('commit_hash', None) api_scan_configuration = form.cleaned_data.get('api_scan_configuration', None) service = form.cleaned_data.get('service', None) close_old_findings = form.cleaned_data.get('close_old_findings', None) # Will save in the provided environment or in the `Development` one if absent environment_id = request.POST.get('environment', 'Development') environment = Development_Environment.objects.get(id=environment_id) group_by = form.cleaned_data.get('group_by', None) # TODO move to form validation? if scan and is_scan_file_too_large(scan): messages.add_message(request, messages.ERROR, "Report file is too large. Maximum supported size is {} MB".format(settings.SCAN_FILE_MAX_SIZE), extra_tags='alert-danger') return HttpResponseRedirect(reverse('import_scan_results', args=(engagement,))) # Allows for a test to be imported with an engagement created on the fly if engagement is None: engagement = Engagement() engagement.name = "AdHoc Import - " + strftime("%a, %d %b %Y %X", timezone.now().timetuple()) engagement.threat_model = False engagement.api_test = False engagement.pen_test = False engagement.check_list = False engagement.target_start = timezone.now().date() engagement.target_end = timezone.now().date() engagement.product = product engagement.active = True engagement.status = 'In Progress' engagement.version = version engagement.branch_tag = branch_tag engagement.build_id = build_id engagement.commit_hash = commit_hash engagement.save() # can't use helper as when push_all_jira_issues is True, the checkbox gets disabled and is always false # push_to_jira = jira_helper.is_push_to_jira(new_finding, jform.cleaned_data.get('push_to_jira')) push_to_jira = push_all_jira_issues or (jform and jform.cleaned_data.get('push_to_jira')) error = False # Save newly added endpoints added_endpoints = save_endpoints_to_add(form.endpoints_to_add_list, engagement.product) try: importer = Importer() test, finding_count, closed_finding_count = importer.import_scan(scan, scan_type, engagement, user, environment, active=active, verified=verified, tags=tags, minimum_severity=minimum_severity, endpoints_to_add=list(form.cleaned_data['endpoints']) + added_endpoints, scan_date=scan_date, version=version, branch_tag=branch_tag, build_id=build_id, commit_hash=commit_hash, push_to_jira=push_to_jira, close_old_findings=close_old_findings, group_by=group_by, api_scan_configuration=api_scan_configuration, service=service) message = f'{scan_type} processed a total of {finding_count} findings' if close_old_findings: message = message + ' and closed %d findings' % (closed_finding_count) message = message + "." add_success_message_to_response(message) except Exception as e: logger.exception(e) add_error_message_to_response('An exception error occurred during the report import:%s' % str(e)) error = True # Save the credential to the test if cred_form.is_valid(): if cred_form.cleaned_data['cred_user']: # Select the credential mapping object from the selected list and only allow if the credential is associated with the product cred_user = Cred_Mapping.objects.filter( pk=cred_form.cleaned_data['cred_user'].id, engagement=eid).first() new_f = cred_form.save(commit=False) new_f.test = test new_f.cred_id = cred_user.cred_id new_f.save() if not error: return HttpResponseRedirect( reverse('view_test', args=(test.id, ))) prod_id = None custom_breadcrumb = None title = "Import Scan Results" if engagement: prod_id = engagement.product.id product_tab = Product_Tab(prod_id, title=title, tab="engagements") product_tab.setEngagement(engagement) else: prod_id = pid custom_breadcrumb = {"", ""} product_tab = Product_Tab(prod_id, title=title, tab="findings") if jira_helper.get_jira_project(engagement_or_product): jform = JIRAImportScanForm(push_all=push_all_jira_issues, prefix='jiraform') form.fields['endpoints'].queryset = Endpoint.objects.filter(product__id=product_tab.product.id) form.fields['api_scan_configuration'].queryset = Product_API_Scan_Configuration.objects.filter(product__id=product_tab.product.id) return render(request, 'dojo/import_scan_results.html', {'form': form, 'product_tab': product_tab, 'engagement_or_product': engagement_or_product, 'custom_breadcrumb': custom_breadcrumb, 'title': title, 'cred_form': cred_form, 'jform': jform, 'scan_types': get_scan_types_sorted(), })
def re_import_scan_results(request, tid): additional_message = "When re-uploading a scan, any findings not found in original scan will be updated as " \ "mitigated. The process attempts to identify the differences, however manual verification " \ "is highly recommended." test = get_object_or_404(Test, id=tid) scan_type = test.test_type.name engagement = test.engagement form = ReImportScanForm() jform = None push_all_jira_issues = False # Decide if we need to present the Push to JIRA form if get_system_setting( 'enable_jira') and engagement.product.jira_pkey_set.first( ) is not None: push_all_jira_issues = engagement.product.jira_pkey_set.first( ).push_all_issues jform = JIRAImportScanForm(push_all=push_all_jira_issues, prefix='jiraform') form.initial['tags'] = [tag.name for tag in test.tags] if request.method == "POST": form = ReImportScanForm(request.POST, request.FILES) if form.is_valid(): scan_date = form.cleaned_data['scan_date'] scan_date_time = datetime.combine(scan_date, timezone.now().time()) if settings.USE_TZ: scan_date_time = timezone.make_aware( scan_date_time, timezone.get_default_timezone()) min_sev = form.cleaned_data['minimum_severity'] file = request.FILES.get('file', None) scan_type = test.test_type.name active = form.cleaned_data['active'] verified = form.cleaned_data['verified'] tags = request.POST.getlist('tags') ts = ", ".join(tags) test.tags = ts if file and is_scan_file_too_large(file): messages.add_message( request, messages.ERROR, "Report file is too large. Maximum supported size is {} MB" .format(settings.SCAN_FILE_MAX_SIZE), extra_tags='alert-danger') return HttpResponseRedirect( reverse('re_import_scan_results', args=(test.id, ))) try: parser = import_parser_factory(file, test, active, verified) except ValueError: raise Http404() except Exception as e: messages.add_message( request, messages.ERROR, "An error has occurred in the parser, please see error " "log for details.", extra_tags='alert-danger') parse_logger.exception(e) parse_logger.error("Error in parser: {}".format(str(e))) return HttpResponseRedirect( reverse('re_import_scan_results', args=(test.id, ))) try: items = parser.items original_items = test.finding_set.all().values_list("id", flat=True) new_items = [] mitigated_count = 0 finding_count = 0 finding_added_count = 0 reactivated_count = 0 # Push to Jira? push_to_jira = False if push_all_jira_issues: push_to_jira = True elif 'jiraform-push_to_jira' in request.POST: jform = JIRAImportScanForm(request.POST, prefix='jiraform', push_all=push_all_jira_issues) if jform.is_valid(): push_to_jira = jform.cleaned_data.get('push_to_jira') for item in items: sev = item.severity if sev == 'Information' or sev == 'Informational': sev = 'Info' item.severity = sev # existing findings may be from before we had component_name/version fields component_name = item.component_name if hasattr( item, 'component_name') else None component_version = item.component_version if hasattr( item, 'component_version') else None # If it doesn't clear minimum severity, move on if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]: continue # Try to find the existing finding # If it's Veracode or Arachni, then we consider the description for some # reason... from titlecase import titlecase item.title = titlecase(item.title) if scan_type == 'Veracode Scan' or scan_type == 'Arachni Scan': finding = Finding.objects.filter( title=item.title, test__id=test.id, severity=sev, numerical_severity=Finding.get_numerical_severity( sev), description=item.description) else: finding = Finding.objects.filter( title=item.title, test__id=test.id, severity=sev, numerical_severity=Finding.get_numerical_severity( sev)) if len(finding) == 1: finding = finding[0] if finding.mitigated or finding.is_Mitigated: # it was once fixed, but now back finding.mitigated = None finding.is_Mitigated = False finding.mitigated_by = None finding.active = True finding.verified = verified # existing findings may be from before we had component_name/version fields finding.component_name = finding.component_name if finding.component_name else component_name finding.component_version = finding.component_version if finding.component_version else component_version finding.save() note = Notes( entry="Re-activated by %s re-upload." % scan_type, author=request.user) note.save() finding.notes.add(note) endpoint_status = finding.endpoint_status.all() for status in endpoint_status: status.mitigated_by = None status.mitigated_time = None status.mitigated = False status.last_modified = timezone.now() status.save() reactivated_count += 1 else: # existing findings may be from before we had component_name/version fields if not finding.component_name or not finding.component_version: finding.component_name = finding.component_name if finding.component_name else component_name finding.component_version = finding.component_version if finding.component_version else component_version finding.save(dedupe_option=False, push_to_jira=False) new_items.append(finding.id) else: item.test = test if item.date == timezone.now().date(): item.date = test.target_start.date() item.reporter = request.user item.last_reviewed = timezone.now() item.last_reviewed_by = request.user item.verified = verified item.active = active # Save it item.save(dedupe_option=False) finding_added_count += 1 # Add it to the new items new_items.append(item.id) finding = item if hasattr(item, 'unsaved_req_resp') and len( item.unsaved_req_resp) > 0: for req_resp in item.unsaved_req_resp: if scan_type == "Arachni Scan": burp_rr = BurpRawRequestResponse( finding=item, burpRequestBase64=req_resp["req"], burpResponseBase64=req_resp["resp"], ) else: burp_rr = BurpRawRequestResponse( finding=item, burpRequestBase64=base64.b64encode( req_resp["req"].encode("utf-8")), burpResponseBase64=base64.b64encode( req_resp["resp"].encode("utf-8")), ) burp_rr.clean() burp_rr.save() if item.unsaved_request is not None and item.unsaved_response is not None: burp_rr = BurpRawRequestResponse( finding=finding, burpRequestBase64=base64.b64encode( item.unsaved_request.encode()), burpResponseBase64=base64.b64encode( item.unsaved_response.encode()), ) burp_rr.clean() burp_rr.save() if finding: finding_count += 1 for endpoint in item.unsaved_endpoints: ep, created = Endpoint.objects.get_or_create( protocol=endpoint.protocol, host=endpoint.host, path=endpoint.path, query=endpoint.query, fragment=endpoint.fragment, product=test.engagement.product) eps, created = Endpoint_Status.objects.get_or_create( finding=finding, endpoint=ep) ep.endpoint_status.add(eps) finding.endpoints.add(ep) finding.endpoint_status.add(eps) for endpoint in form.cleaned_data['endpoints']: ep, created = Endpoint.objects.get_or_create( protocol=endpoint.protocol, host=endpoint.host, path=endpoint.path, query=endpoint.query, fragment=endpoint.fragment, product=test.engagement.product) eps, created = Endpoint_Status.objects.get_or_create( finding=finding, endpoint=ep) ep.endpoint_status.add(eps) finding.endpoints.add(ep) finding.endpoint_status.add(eps) if item.unsaved_tags is not None: finding.tags = item.unsaved_tags # Save it. This may be the second time we save it in this function. finding.save(push_to_jira=push_to_jira) # calculate the difference to_mitigate = set(original_items) - set(new_items) for finding_id in to_mitigate: finding = Finding.objects.get(id=finding_id) if not finding.mitigated or not finding.is_Mitigated: finding.mitigated = scan_date_time finding.is_Mitigated = True finding.mitigated_by = request.user finding.active = False finding.save() note = Notes(entry="Mitigated by %s re-upload." % scan_type, author=request.user) note.save() finding.notes.add(note) mitigated_count += 1 endpoint_status = finding.endpoint_status.all() for status in endpoint_status: status.mitigated_by = request.user status.mitigated_time = timezone.now() status.mitigated = True status.last_modified = timezone.now() status.save() test.updated = max_safe([scan_date_time, test.updated]) test.engagement.updated = max_safe( [scan_date_time, test.engagement.updated]) test.save() test.engagement.save() messages.add_message( request, messages.SUCCESS, '%s processed, a total of ' % scan_type + message(finding_count, 'finding', 'processed'), extra_tags='alert-success') if finding_added_count > 0: messages.add_message( request, messages.SUCCESS, 'A total of ' + message(finding_added_count, 'finding', 'added') + ', that are new to scan.', extra_tags='alert-success') if reactivated_count > 0: messages.add_message( request, messages.SUCCESS, 'A total of ' + message(reactivated_count, 'finding', 'reactivated') + ', that are back in scan results.', extra_tags='alert-success') if mitigated_count > 0: messages.add_message( request, messages.SUCCESS, 'A total of ' + message(mitigated_count, 'finding', 'mitigated') + '. Please manually verify each one.', extra_tags='alert-success') create_notification(event='scan_added', title=str(finding_count) + " findings for " + test.engagement.product.name, finding_count=finding_count, test=test, engagement=test.engagement, url=reverse('view_test', args=(test.id, ))) return HttpResponseRedirect( reverse('view_test', args=(test.id, ))) except SyntaxError: messages.add_message( request, messages.ERROR, 'There appears to be an error in the XML report, please check and try again.', extra_tags='alert-danger') product_tab = Product_Tab(engagement.product.id, title="Re-upload a %s" % scan_type, tab="engagements") product_tab.setEngagement(engagement) form.fields['endpoints'].queryset = Endpoint.objects.filter( product__id=product_tab.product.id) return render( request, 'dojo/import_scan_results.html', { 'form': form, 'product_tab': product_tab, 'eid': engagement.id, 'additional_message': additional_message, 'jform': jform, })
def view_edit_risk_acceptance(request, eid, raid, edit_mode=False): risk_acceptance = get_object_or_404(Risk_Acceptance, pk=raid) eng = get_object_or_404(Engagement, pk=eid) if edit_mode and not eng.product.enable_full_risk_acceptance: raise PermissionDenied() risk_acceptance_form = None errors = False if request.method == 'POST': # deleting before instantiating the form otherwise django messes up and we end up with an empty path value if len(request.FILES) > 0: logger.debug('new proof uploaded') risk_acceptance.path.delete() if 'decision' in request.POST: old_expiration_date = risk_acceptance.expiration_date risk_acceptance_form = EditRiskAcceptanceForm(request.POST, request.FILES, instance=risk_acceptance) errors = errors or not risk_acceptance_form.is_valid() if not errors: logger.debug('path: %s', risk_acceptance_form.cleaned_data['path']) risk_acceptance_form.save() if risk_acceptance.expiration_date != old_expiration_date: # risk acceptance was changed, check if risk acceptance needs to be reinstated and findings made accepted again ra_helper.reinstate(risk_acceptance, old_expiration_date) messages.add_message( request, messages.SUCCESS, 'Risk Acceptance saved successfully.', extra_tags='alert-success') if 'entry' in request.POST: note_form = NoteForm(request.POST) errors = errors or not note_form.is_valid() if not errors: new_note = note_form.save(commit=False) new_note.author = request.user new_note.date = timezone.now() new_note.save() risk_acceptance.notes.add(new_note) messages.add_message( request, messages.SUCCESS, 'Note added successfully.', extra_tags='alert-success') if 'delete_note' in request.POST: note = get_object_or_404(Notes, pk=request.POST['delete_note_id']) if note.author.username == request.user.username: risk_acceptance.notes.remove(note) note.delete() messages.add_message( request, messages.SUCCESS, 'Note deleted successfully.', extra_tags='alert-success') else: messages.add_message( request, messages.ERROR, "Since you are not the note's author, it was not deleted.", extra_tags='alert-danger') if 'remove_finding' in request.POST: finding = get_object_or_404( Finding, pk=request.POST['remove_finding_id']) ra_helper.remove_finding_from_risk_acceptance(risk_acceptance, finding) messages.add_message( request, messages.SUCCESS, 'Finding removed successfully from risk acceptance.', extra_tags='alert-success') if 'replace_file' in request.POST: replace_form = ReplaceRiskAcceptanceProofForm( request.POST, request.FILES, instance=risk_acceptance) errors = errors or not replace_form.is_valid() if not errors: replace_form.save() messages.add_message( request, messages.SUCCESS, 'New Proof uploaded successfully.', extra_tags='alert-success') else: logger.error(replace_form.errors) if 'add_findings' in request.POST: add_findings_form = AddFindingsRiskAcceptanceForm( request.POST, request.FILES, instance=risk_acceptance) errors = errors or not add_findings_form.is_valid() if not errors: findings = add_findings_form.cleaned_data['accepted_findings'] ra_helper.add_findings_to_risk_acceptance(risk_acceptance, findings) messages.add_message( request, messages.SUCCESS, 'Finding%s added successfully.' % ('s' if len(findings) > 1 else ''), extra_tags='alert-success') if not errors: logger.debug('redirecting to return_url') return redirect_to_return_url_or_else(request, reverse("view_risk_acceptance", args=(eid, raid))) else: logger.error('errors found') else: if edit_mode: risk_acceptance_form = EditRiskAcceptanceForm(instance=risk_acceptance) note_form = NoteForm() replace_form = ReplaceRiskAcceptanceProofForm(instance=risk_acceptance) add_findings_form = AddFindingsRiskAcceptanceForm(instance=risk_acceptance) accepted_findings = risk_acceptance.accepted_findings.order_by('numerical_severity') fpage = get_page_items(request, accepted_findings, 15) unaccepted_findings = Finding.objects.filter(test__in=eng.test_set.all()) \ .exclude(id__in=accepted_findings).order_by("title") add_fpage = get_page_items(request, unaccepted_findings, 10, 'apage') # on this page we need to add unaccepted findings as possible findings to add as accepted add_findings_form.fields[ "accepted_findings"].queryset = add_fpage.object_list product_tab = Product_Tab(eng.product.id, title="Risk Acceptance", tab="engagements") product_tab.setEngagement(eng) return render( request, 'dojo/view_risk_acceptance.html', { 'risk_acceptance': risk_acceptance, 'engagement': eng, 'product_tab': product_tab, 'accepted_findings': fpage, 'notes': risk_acceptance.notes.all(), 'eng': eng, 'edit_mode': edit_mode, 'risk_acceptance_form': risk_acceptance_form, 'note_form': note_form, 'replace_form': replace_form, 'add_findings_form': add_findings_form, # 'show_add_findings_form': len(unaccepted_findings), 'request': request, 'add_findings': add_fpage, 'return_url': get_return_url(request), })
def add_findings(request, tid): test = Test.objects.get(id=tid) form_error = False jform = None form = AddFindingForm(initial={'date': timezone.now().date()}, req_resp=None, product=test.engagement.product) push_all_jira_issues = jira_helper.is_push_all_issues(test) use_jira = jira_helper.get_jira_project(test) is not None if request.method == 'POST': form = AddFindingForm(request.POST, req_resp=None, product=test.engagement.product) if (form['active'].value() is False or form['false_p'].value() ) and form['duplicate'].value() is False: closing_disabled = Note_Type.objects.filter( is_mandatory=True, is_active=True).count() if closing_disabled != 0: error_inactive = ValidationError( 'Can not set a finding as inactive without adding all mandatory notes', code='inactive_without_mandatory_notes') error_false_p = ValidationError( 'Can not set a finding as false positive without adding all mandatory notes', code='false_p_without_mandatory_notes') if form['active'].value() is False: form.add_error('active', error_inactive) if form['false_p'].value(): form.add_error('false_p', error_false_p) messages.add_message( request, messages.ERROR, 'Can not set a finding as inactive or false positive without adding all mandatory notes', extra_tags='alert-danger') if use_jira: jform = JIRAFindingForm( request.POST, prefix='jiraform', push_all=push_all_jira_issues, jira_project=jira_helper.get_jira_project(test), finding_form=form) if form.is_valid() and (jform is None or jform.is_valid()): if jform: logger.debug('jform.jira_issue: %s', jform.cleaned_data.get('jira_issue')) logger.debug('jform.push_to_jira: %s', jform.cleaned_data.get('push_to_jira')) new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) new_finding.tags = form.cleaned_data['tags'] new_finding.save(dedupe_option=False, push_to_jira=False) # Save and add new endpoints finding_helper.add_endpoints(new_finding, form) # Push to jira? push_to_jira = False jira_message = None if jform and jform.is_valid(): # can't use helper as when push_all_jira_issues is True, the checkbox gets disabled and is always false # push_to_jira = jira_helper.is_push_to_jira(new_finding, jform.cleaned_data.get('push_to_jira')) push_to_jira = push_all_jira_issues or jform.cleaned_data.get( 'push_to_jira') # if the jira issue key was changed, update database new_jira_issue_key = jform.cleaned_data.get('jira_issue') if new_finding.has_jira_issue: jira_issue = new_finding.jira_issue # everything in DD around JIRA integration is based on the internal id of the issue in JIRA # instead of on the public jira issue key. # I have no idea why, but it means we have to retrieve the issue from JIRA to get the internal JIRA id. # we can assume the issue exist, which is already checked in the validation of the jform if not new_jira_issue_key: jira_helper.finding_unlink_jira(request, new_finding) jira_message = 'Link to JIRA issue removed successfully.' elif new_jira_issue_key != new_finding.jira_issue.jira_key: jira_helper.finding_unlink_jira(request, new_finding) jira_helper.finding_link_jira(request, new_finding, new_jira_issue_key) jira_message = 'Changed JIRA link successfully.' else: logger.debug('finding has no jira issue yet') if new_jira_issue_key: logger.debug( 'finding has no jira issue yet, but jira issue specified in request. trying to link.' ) jira_helper.finding_link_jira(request, new_finding, new_jira_issue_key) jira_message = 'Linked a JIRA issue successfully.' new_finding.save(false_history=True, push_to_jira=push_to_jira) create_notification(event='other', title='Addition of %s' % new_finding.title, finding=new_finding, description='Finding "%s" was added by %s' % (new_finding.title, request.user), url=request.build_absolute_uri( reverse('view_finding', args=(new_finding.id, ))), icon="exclamation-triangle") if 'request' in form.cleaned_data or 'response' in form.cleaned_data: burp_rr = BurpRawRequestResponse( finding=new_finding, burpRequestBase64=base64.b64encode( form.cleaned_data['request'].encode()), burpResponseBase64=base64.b64encode( form.cleaned_data['response'].encode()), ) burp_rr.clean() burp_rr.save() if '_Finished' in request.POST: return HttpResponseRedirect( reverse('view_test', args=(test.id, ))) else: return HttpResponseRedirect( reverse('add_findings', args=(test.id, ))) else: form_error = True add_error_message_to_response( 'The form has errors, please correct them below.') add_field_errors_to_response(jform) add_field_errors_to_response(form) else: if use_jira: jform = JIRAFindingForm( push_all=jira_helper.is_push_all_issues(test), prefix='jiraform', jira_project=jira_helper.get_jira_project(test), finding_form=form) product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render( request, 'dojo/add_findings.html', { 'form': form, 'product_tab': product_tab, 'test': test, 'temp': False, 'tid': tid, 'form_error': form_error, 'jform': jform, })
def add_temp_finding(request, tid, fid): jform = None test = get_object_or_404(Test, id=tid) finding = get_object_or_404(Finding_Template, id=fid) findings = Finding_Template.objects.all() if request.method == 'POST': form = FindingForm(request.POST, template=True) if form.is_valid(): finding.last_used = timezone.now() finding.save() new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) new_finding.date = datetime.today() if new_finding.false_p or new_finding.active is False: new_finding.mitigated = timezone.now() new_finding.mitigated_by = request.user create_template = new_finding.is_template # is template always False now in favor of new model Finding_Template # no further action needed here since this is already adding from template. new_finding.is_template = False new_finding.save(dedupe_option=False, false_history=False) new_finding.endpoints.set(form.cleaned_data['endpoints']) new_finding.save(false_history=True) tags = request.POST.getlist('tags') t = ", ".join(tags) new_finding.tags = t if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=True) if jform.is_valid(): add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira')) messages.add_message(request, messages.SUCCESS, 'Finding from template added successfully.', extra_tags='alert-success') if create_template: templates = Finding_Template.objects.filter(title=new_finding.title) if len(templates) > 0: messages.add_message(request, messages.ERROR, 'A finding template was not created. A template with this title already ' 'exists.', extra_tags='alert-danger') else: template = Finding_Template(title=new_finding.title, cwe=new_finding.cwe, severity=new_finding.severity, description=new_finding.description, mitigation=new_finding.mitigation, impact=new_finding.impact, references=new_finding.references, numerical_severity=new_finding.numerical_severity) template.save() messages.add_message(request, messages.SUCCESS, 'A finding template was also created.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_test', args=(test.id,))) else: messages.add_message(request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') else: form = FindingForm(template=True, initial={'active': False, 'date': timezone.now().date(), 'verified': False, 'false_p': False, 'duplicate': False, 'out_of_scope': False, 'title': finding.title, 'description': finding.description, 'cwe': finding.cwe, 'severity': finding.severity, 'mitigation': finding.mitigation, 'impact': finding.impact, 'references': finding.references, 'numerical_severity': finding.numerical_severity, 'tags': [tag.name for tag in finding.tags]}) if get_system_setting('enable_jira'): enabled = JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues jform = JIRAFindingForm(enabled=enabled, prefix='jiraform') else: jform = None product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render(request, 'dojo/add_findings.html', {'form': form, 'product_tab': product_tab, 'jform': jform, 'findings': findings, 'temp': True, 'fid': finding.id, 'tid': test.id, 'test': test, })
def view_test(request, tid): test_prefetched = get_authorized_tests(Permissions.Test_View) test_prefetched = test_prefetched.annotate( total_reimport_count=Count('test_import__id', distinct=True)) # tests_prefetched = test_prefetched.prefetch_related(Prefetch('test_import_set', queryset=Test_Import.objects.filter(~Q(findings_affected=None)))) # tests_prefetched = test_prefetched.prefetch_related('test_import_set') # test_prefetched = test_prefetched.prefetch_related('test_import_set__test_import_finding_action_set') test = get_object_or_404(test_prefetched, pk=tid) # test = get_object_or_404(Test, pk=tid) prod = test.engagement.product notes = test.notes.all() note_type_activation = Note_Type.objects.filter(is_active=True).count() if note_type_activation: available_note_types = find_available_notetypes(notes) files = test.files.all() person = request.user.username findings = Finding.objects.filter(test=test).order_by('numerical_severity') findings = FindingFilter(request.GET, queryset=findings) stub_findings = Stub_Finding.objects.filter(test=test) cred_test = Cred_Mapping.objects.filter( test=test).select_related('cred_id').order_by('cred_id') creds = Cred_Mapping.objects.filter( engagement=test.engagement).select_related('cred_id').order_by( 'cred_id') system_settings = get_object_or_404(System_Settings, id=1) if request.method == 'POST': user_has_permission_or_403(request.user, test, Permissions.Note_Add) if note_type_activation: form = TypedNoteForm(request.POST, available_note_types=available_note_types) else: form = NoteForm(request.POST) if form.is_valid(): new_note = form.save(commit=False) new_note.author = request.user new_note.date = timezone.now() new_note.save() test.notes.add(new_note) if note_type_activation: form = TypedNoteForm(available_note_types=available_note_types) else: form = NoteForm() url = request.build_absolute_uri( reverse("view_test", args=(test.id, ))) title = "Test: %s on %s" % (test.test_type.name, test.engagement.product.name) process_notifications(request, new_note, url, title) messages.add_message(request, messages.SUCCESS, 'Note added successfully.', extra_tags='alert-success') else: if note_type_activation: form = TypedNoteForm(available_note_types=available_note_types) else: form = NoteForm() title_words = get_words_for_field(Finding, 'title') component_words = get_words_for_field(Finding, 'component_name') # test_imports = test.test_import_set.all() test_imports = Test_Import.objects.filter(test=test) test_import_filter = TestImportFilter(request.GET, test_imports) paged_test_imports = get_page_items_and_count(request, test_import_filter.qs, 5, prefix='test_imports') paged_test_imports.object_list = paged_test_imports.object_list.prefetch_related( 'test_import_finding_action_set') paged_findings = get_page_items_and_count(request, prefetch_for_findings( findings.qs), 25, prefix='findings') paged_stub_findings = get_page_items(request, stub_findings, 25) show_re_upload = any(test.test_type.name in code for code in get_choices_sorted()) product_tab = Product_Tab(prod.id, title="Test", tab="engagements") product_tab.setEngagement(test.engagement) jira_project = jira_helper.get_jira_project(test) finding_groups = test.finding_group_set.all().prefetch_related( 'findings', 'jira_issue', 'creator') bulk_edit_form = FindingBulkUpdateForm(request.GET) google_sheets_enabled = system_settings.enable_google_sheets sheet_url = None if google_sheets_enabled and system_settings.credentials: spreadsheet_name = test.engagement.product.name + "-" + test.engagement.name + "-" + str( test.id) system_settings = get_object_or_404(System_Settings, id=1) service_account_info = json.loads(system_settings.credentials) SCOPES = ['https://www.googleapis.com/auth/drive'] credentials = service_account.Credentials.from_service_account_info( service_account_info, scopes=SCOPES) try: drive_service = googleapiclient.discovery.build( 'drive', 'v3', credentials=credentials, cache_discovery=False) folder_id = system_settings.drive_folder_ID gs_files = drive_service.files().list( q="mimeType='application/vnd.google-apps.spreadsheet' and parents in '%s' and name='%s'" % (folder_id, spreadsheet_name), spaces='drive', pageSize=10, fields='files(id, name)').execute() except googleapiclient.errors.HttpError: messages.add_message( request, messages.ERROR, "There is a problem with the Google Sheets Sync Configuration. Contact your system admin to solve the issue. Until fixed, the Google Sheets Sync feature cannot be used.", extra_tags="alert-danger", ) google_sheets_enabled = False except httplib2.ServerNotFoundError: messages.add_message( request, messages.ERROR, "Unable to reach the Google Sheet API.", extra_tags="alert-danger", ) else: spreadsheets = gs_files.get('files') if len(spreadsheets) == 1: spreadsheetId = spreadsheets[0].get('id') sheet_url = 'https://docs.google.com/spreadsheets/d/' + spreadsheetId return render( request, 'dojo/view_test.html', { 'test': test, 'prod': prod, 'product_tab': product_tab, 'findings': paged_findings, 'filtered': findings, 'stub_findings': paged_stub_findings, 'title_words': title_words, 'component_words': component_words, 'form': form, 'notes': notes, 'files': files, 'person': person, 'request': request, 'show_re_upload': show_re_upload, 'creds': creds, 'cred_test': cred_test, 'jira_project': jira_project, 'show_export': google_sheets_enabled and system_settings.credentials, 'sheet_url': sheet_url, 'bulk_edit_form': bulk_edit_form, 'paged_test_imports': paged_test_imports, 'test_import_filter': test_import_filter, 'finding_groups': finding_groups, 'finding_group_by_options': Finding_Group.GROUP_BY_OPTIONS, })
def add_temp_finding(request, tid, fid): jform = None test = get_object_or_404(Test, id=tid) finding = get_object_or_404(Finding_Template, id=fid) findings = Finding_Template.objects.all() push_all_jira_issues = False if get_system_setting('enable_jira'): push_all_jira_issues = test.engagement.product.jira_pkey_set.first( ).push_all_issues jform = JIRAFindingForm(push_all=push_all_jira_issues, prefix='jiraform', jira_pkey=test.engagement.product.jira_pkey) else: jform = None if request.method == 'POST': form = FindingForm(request.POST, template=True, req_resp=None) if (form['active'].value() is False or form['false_p'].value() ) and form['duplicate'].value() is False: closing_disabled = Note_Type.objects.filter( is_mandatory=True, is_active=True).count() if closing_disabled != 0: error_inactive = ValidationError( 'Can not set a finding as inactive without adding all mandatory notes', code='not_active_or_false_p_true') error_false_p = ValidationError( 'Can not set a finding as false positive without adding all mandatory notes', code='not_active_or_false_p_true') if form['active'].value() is False: form.add_error('active', error_inactive) if form['false_p'].value(): form.add_error('false_p', error_false_p) messages.add_message( request, messages.ERROR, 'Can not set a finding as inactive or false positive without adding all mandatory notes', extra_tags='alert-danger') if form.is_valid(): finding.last_used = timezone.now() finding.save() new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) new_finding.date = datetime.today() if new_finding.false_p or new_finding.active is False: new_finding.mitigated = timezone.now() new_finding.mitigated_by = request.user new_finding.is_Mitigated = True create_template = new_finding.is_template # is template always False now in favor of new model Finding_Template # no further action needed here since this is already adding from template. new_finding.is_template = False new_finding.save(dedupe_option=False, false_history=False) for ep in form.cleaned_data['endpoints']: eps, created = Endpoint_Status.objects.get_or_create( finding=new_finding, endpoint=ep) ep.endpoint_status.add(eps) new_finding.endpoints.add(ep) new_finding.endpoint_status.add(eps) new_finding.save(false_history=True) tags = request.POST.getlist('tags') t = ", ".join('"{0}"'.format(w) for w in tags) new_finding.tags = t if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm( request.POST, prefix='jiraform', push_all=push_all_jira_issues, jira_pkey=test.engagement.product.jira_pkey) if jform.is_valid(): if Dojo_User.wants_block_execution(request.user): add_jira_issue(new_finding, jform.cleaned_data.get('push_to_jira')) else: add_jira_issue_task.delay( new_finding, jform.cleaned_data.get('push_to_jira')) messages.add_message(request, messages.SUCCESS, 'Finding from template added successfully.', extra_tags='alert-success') if create_template: templates = Finding_Template.objects.filter( title=new_finding.title) if len(templates) > 0: messages.add_message( request, messages.ERROR, 'A finding template was not created. A template with this title already ' 'exists.', extra_tags='alert-danger') else: template = Finding_Template( title=new_finding.title, cwe=new_finding.cwe, severity=new_finding.severity, description=new_finding.description, mitigation=new_finding.mitigation, impact=new_finding.impact, references=new_finding.references, numerical_severity=new_finding.numerical_severity) template.save() messages.add_message( request, messages.SUCCESS, 'A finding template was also created.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_test', args=(test.id, ))) else: messages.add_message( request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') else: form = FindingForm(template=True, req_resp=None, initial={ 'active': False, 'date': timezone.now().date(), 'verified': False, 'false_p': False, 'duplicate': False, 'out_of_scope': False, 'title': finding.title, 'description': finding.description, 'cwe': finding.cwe, 'severity': finding.severity, 'mitigation': finding.mitigation, 'impact': finding.impact, 'references': finding.references, 'numerical_severity': finding.numerical_severity, 'tags': [tag.name for tag in finding.tags] }) product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render( request, 'dojo/add_findings.html', { 'form': form, 'product_tab': product_tab, 'jform': jform, 'findings': findings, 'temp': True, 'fid': finding.id, 'tid': test.id, 'test': test, })
def add_temp_finding(request, tid, fid): jform = None test = get_object_or_404(Test, id=tid) finding = get_object_or_404(Finding_Template, id=fid) findings = Finding_Template.objects.all() if request.method == 'POST': form = FindingForm(request.POST) if form.is_valid(): new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) new_finding.date = datetime.today() if new_finding.false_p or new_finding.active is False: new_finding.mitigated = timezone.now() new_finding.mitigated_by = request.user create_template = new_finding.is_template # is template always False now in favor of new model Finding_Template # no further action needed here since this is already adding from template. new_finding.is_template = False new_finding.save(dedupe_option=False, false_history=False) new_finding.endpoints = form.cleaned_data['endpoints'] new_finding.save(false_history=True) if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=True) if jform.is_valid(): add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira')) messages.add_message(request, messages.SUCCESS, 'Finding from template added successfully.', extra_tags='alert-success') if create_template: templates = Finding_Template.objects.filter(title=new_finding.title) if len(templates) > 0: messages.add_message(request, messages.ERROR, 'A finding template was not created. A template with this title already ' 'exists.', extra_tags='alert-danger') else: template = Finding_Template(title=new_finding.title, cwe=new_finding.cwe, severity=new_finding.severity, description=new_finding.description, mitigation=new_finding.mitigation, impact=new_finding.impact, references=new_finding.references, numerical_severity=new_finding.numerical_severity) template.save() messages.add_message(request, messages.SUCCESS, 'A finding template was also created.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_test', args=(test.id,))) else: messages.add_message(request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') else: form = FindingForm(initial={'active': False, 'date': timezone.now().date(), 'verified': False, 'false_p': False, 'duplicate': False, 'out_of_scope': False, 'title': finding.title, 'description': finding.description, 'cwe': finding.cwe, 'severity': finding.severity, 'mitigation': finding.mitigation, 'impact': finding.impact, 'references': finding.references, 'numerical_severity': finding.numerical_severity}) if get_system_setting('enable_jira'): enabled = JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues jform = JIRAFindingForm(enabled=enabled, prefix='jiraform') else: jform = None product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render(request, 'dojo/add_findings.html', {'form': form, 'product_tab': product_tab, 'jform': jform, 'findings': findings, 'temp': True, 'fid': finding.id, 'tid': test.id, 'test': test, })