def finding_sla(finding): if not get_system_setting('enable_finding_sla'): return "" title = "" severity = finding.severity find_sla = finding.sla() sla_age = get_system_setting('sla_' + severity.lower()) if finding.mitigated: status = "blue" status_text = 'Remediated within SLA for ' + severity.lower() + ' findings (' + str(sla_age) + ' days)' if find_sla and find_sla < 0: status = "orange" find_sla = abs(find_sla) status_text = 'Out of SLA: Remediatied ' + str(find_sla) + ' days past SLA for ' + severity.lower() + ' findings (' + str(sla_age) + ' days)' else: status = "green" status_text = 'Remediation for ' + severity.lower() + ' findings in ' + str(sla_age) + ' days or less' if find_sla and find_sla < 0: status = "red" find_sla = abs(find_sla) status_text = 'Overdue: Remediation for ' + severity.lower() + ' findings in ' + str(sla_age) + ' days or less' if find_sla is not None: title = '<a data-toggle="tooltip" data-placement="bottom" title="" href="#" data-original-title="' + status_text + '">' \ '<span class="label severity age-' + status + '">' + str(find_sla) + '</span></a>' return mark_safe(title)
def new_eng_for_app(request, pid, cicd=False): jform = None prod = Product.objects.get(id=pid) if request.method == 'POST': form = EngForm(request.POST, cicd=cicd) if form.is_valid(): new_eng = form.save(commit=False) if not new_eng.name: new_eng.name = str(new_eng.target_start) new_eng.threat_model = False new_eng.api_test = False new_eng.pen_test = False new_eng.check_list = False new_eng.product = prod if new_eng.threat_model: new_eng.progress = 'threat_model' else: new_eng.progress = 'other' if cicd: new_eng.engagement_type = 'CI/CD' new_eng.status = "In Progress" new_eng.save() tags = request.POST.getlist('tags') t = ", ".join(tags) new_eng.tags = t if get_system_setting('enable_jira'): # Test to make sure there is a Jira project associated the product try: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=JIRA_PKey.objects.get(product=prod).push_all_issues) if jform.is_valid(): add_epic_task.delay(new_eng, jform.cleaned_data.get('push_to_jira')) except JIRA_PKey.DoesNotExist: pass messages.add_message(request, messages.SUCCESS, 'Engagement added successfully.', extra_tags='alert-success') create_notification(event='engagement_added', title=new_eng.name + " for " + prod.name, engagement=new_eng, url=request.build_absolute_uri(reverse('view_engagement', args=(new_eng.id,))), objowner=new_eng.lead) if "_Add Tests" in request.POST: return HttpResponseRedirect(reverse('add_tests', args=(new_eng.id,))) elif "_Import Scan Results" in request.POST: return HttpResponseRedirect(reverse('import_scan_results', args=(new_eng.id,))) else: return HttpResponseRedirect(reverse('view_engagement', args=(new_eng.id,))) else: form = EngForm(initial={'lead': request.user, 'target_start': timezone.now().date(), 'target_end': timezone.now().date() + timedelta(days=7)}, cicd=cicd, product=prod.id) if(get_system_setting('enable_jira')): if JIRA_PKey.objects.filter(product=prod).count() != 0: jform = JIRAFindingForm(prefix='jiraform', enabled=JIRA_PKey.objects.get(product=prod).push_all_issues) product_tab = Product_Tab(pid, title="New Engagement", tab="engagements") return render(request, 'dojo/new_eng.html', {'form': form, 'pid': pid, 'product_tab': product_tab, 'jform': jform })
def runScan(prod_id, p_dict): ipScan_queue = Queue.Queue(50) for host in p_dict: current_scan = Scan.objects.get(id=p_dict[host]['scan_id']) if not current_scan.date: current_scan.date = locale.localize(datetime.today()) # For each host, save the IPScan and the date to the scan # to the db ipScan_queue.put((host, p_dict[host])) ipscan_thread = threadedIPScan(ipScan_queue) ipscan_thread.setDaemon(True) ipscan_thread.start() ipScan_queue.join() # Compare the results to the expected ports and email results if # necessary product = Product.objects.get(id=prod_id).name msg = "Hello, \n\nA port scan of the product " + product msg += " was performed on " + locale.normalize( current_scan.date).strftime("%A %B %d, %Y at %I:%M:%S %p") msg += "\nThe results of the scan show that the following ip " msg += "addresses have the following ports open: \n\n" for host in p_dict: msg += str(host) + ": \n" for p in p_dict[host]['result']: msg += str(p) + " \n" scans_same_setting = Scan.objects.filter( scan_settings=current_scan.scan_settings) diff = p_dict[host]['result'] - p_dict[host]['expected'] if diff and len(scans_same_setting) > 1: msg += '\nThese ports appear in this scan but were not ' msg += 'open in the previous scan:\n ' msg += '****** Please ensure that these ports are open if ' msg += 'and only if you have meant it that way ******\n' msg += str(host) + ": \n" for d in diff: msg += str(d) + " \n" msg += "\nYou are receiving this email because you have signed up " msg += "for a port scan on the product security test dojo.\n" msg += "\nFor any questions please email " msg += settings.PORT_SCAN_CONTACT_EMAIL + "\n" msg += "Thanks,\nThe " msg += get_system_setting('team_name') msg += " Team" email_to = current_scan.scan_settings.email send_mail(get_system_setting('team_name') + ' Port Scan Report', msg, settings.PORT_SCAN_RESULT_EMAIL_FROM, [email_to], fail_silently=False)
def new_eng_for_app(request, pid): jform = None prod = Product.objects.get(id=pid) if request.method == 'POST': form = EngForm(request.POST) if form.is_valid(): new_eng = form.save(commit=False) new_eng.product = prod if new_eng.threat_model: new_eng.progress = 'threat_model' else: new_eng.progress = 'other' new_eng.save() if get_system_setting('enable_jira'): #Test to make sure there is a Jira project associated the product try: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=JIRA_PKey.objects.get(product=prod).push_all_issues) if jform.is_valid(): add_epic_task.delay(new_eng, jform.cleaned_data.get('push_to_jira')) except JIRA_PKey.DoesNotExist: pass #else: # print >>sys.stderr, 'no prefix is found' messages.add_message(request, messages.SUCCESS, 'Engagement added successfully.', extra_tags='alert-success') create_notification(event='engagement_added', title='Engagement added', engagement=new_eng, url=request.build_absolute_uri(reverse('view_engagement', args=(new_eng.id,))), objowner=new_eng.lead) if "_Add Tests" in request.POST: return HttpResponseRedirect(reverse('add_tests', args=(new_eng.id,))) else: return HttpResponseRedirect(reverse('view_engagement', args=(new_eng.id,))) else: form = EngForm(initial={}) if(get_system_setting('enable_jira')): if JIRA_PKey.objects.filter(product=prod).count() != 0: jform = JIRAFindingForm(prefix='jiraform', enabled=JIRA_PKey.objects.get(product=prod).push_all_issues) add_breadcrumb(parent=prod, title="New Engagement", top_level=False, request=request) return render(request, 'dojo/new_eng.html', {'form': form, 'pid': pid, 'jform': jform })
def webhook(request): # Webhook shouldn't be active if jira isn't enabled if not get_system_setting('enable_jira'): raise PermissionDenied elif not get_system_setting('enable_jira_web_hook'): raise PermissionDenied if request.method == 'POST': parsed = json.loads(request.body) if 'issue' in parsed.keys(): jid = parsed['issue']['id'] jissue = get_object_or_404(JIRA_Issue, jira_id=jid) if jissue.finding is not None: finding = jissue.finding resolved = True if parsed['issue']['fields']['resolution'] is None: resolved = False if finding.active == resolved: if finding.active: now = timezone.now() finding.active = False finding.mitigated = now finding.endpoints.clear() else: finding.active = True finding.mitigated = None finding.save() finding.save() """ if jissue.engagement is not None: eng = jissue.engagement if parsed['issue']['fields']['resolution'] != None: eng.active = False eng.status = 'Completed' eng.save() """ else: comment_text = parsed['comment']['body'] commentor = parsed['comment']['updateAuthor']['displayName'] jid = parsed['comment']['self'].split('/')[7] jissue = JIRA_Issue.objects.get(jira_id=jid) finding = jissue.finding new_note = Notes() new_note.entry = '(%s): %s' % (commentor, comment_text) new_note.author, created = User.objects.get_or_create(username='******') new_note.save() finding.notes.add(new_note) finding.save() return HttpResponse('')
def all_endpoints(request): endpoints = Endpoint.objects.all() show_uri = get_system_setting('display_endpoint_uri') # are they authorized if request.user.is_staff: pass else: products = Product.objects.filter(authorized_users__in=[request.user]) if products.exists(): endpoints = endpoints.filter(product__in=products.all()) else: raise PermissionDenied product = None if 'product' in request.GET: p = request.GET.getlist('product', []) if len(p) == 1: product = get_object_or_404(Product, id=p[0]) ids = get_endpoint_ids(EndpointFilter(request.GET, queryset=endpoints, user=request.user).qs) if show_uri: paged_endpoints = get_page_items(request, endpoints, 25) else: endpoints = EndpointFilter(request.GET, queryset=endpoints.filter(id__in=ids), user=request.user) paged_endpoints = get_page_items(request, endpoints.qs, 25) add_breadcrumb(title="All Endpoints", top_level=not len(request.GET), request=request) return render(request, 'dojo/endpoints.html', {"endpoints": paged_endpoints, "filtered": endpoints, "name": "All Endpoints", "show_uri": show_uri })
def severity_value(value): try: if get_system_setting('s_finding_severity_naming'): value = Finding.get_numerical_severity(value) except: pass return value
def handle(self, *args, **options): type = options['type'] if not options: print "Must specify an argument: Weekly, Monthly, or Quarterly" sys.exit(0) if type not in ["Weekly", "Monthly", "Quarterly"]: print("Unexpected frequency: " + str(type) + "\nMust specify an argument: Weekly, Monthly, or Quarterly.") sys.exit(0) scSettings = ScanSettings.objects.filter(frequency=type) scan_start_time = datetime.datetime.today() + datetime.timedelta( hours=12) scan_stop_time = datetime.datetime.today() + datetime.timedelta( hours=24) # Send one giant email to External Unit with a list of all the # ipaddresses that will be scanned msg = "\nGreetings, \n\n" msg += get_system_setting('team_name') + " will be performing port scans of " msg += "the following products and target IPs:" msg += "\n\nStart Time: " + str(scan_start_time) msg += "\n\nStop Time (est): " + str(scan_stop_time) msg += "\n\nSource IP: " + settings.PORT_SCAN_SOURCE_IP for s in scSettings: msg += "\n\nProduct: " + str(Product.objects.get( id=s.product_id).name) list_addresses = s.addresses.strip().split(",") for la in list_addresses: line = la.split(":") addr = line[0].strip() msg += "\n" + str(addr) msg += "\n\nPlease let us know if you have any questions.\n Thanks,\n" msg += settings.PORT_SCAN_RESULT_EMAIL_FROM send_mail(get_system_setting('team_name') + ' Port Scan', msg, settings.PORT_SCAN_RESULT_EMAIL_FROM, settings.PORT_SCAN_EXTERNAL_UNIT_EMAIL_LIST, fail_silently=False)
def critical_product_metrics(request, mtype): template = 'dojo/metrics.html' page_name = 'Critical Product Metrics' critical_products = Product_Type.objects.filter(critical_product=True) add_breadcrumb(title=page_name, top_level=not len(request.GET), request=request) return render(request, template, { 'name': page_name, 'critical_prods': critical_products, 'url_prefix': get_system_setting('url_prefix') })
def new_product(request): jform = None if request.method == 'POST': form = ProductForm(request.POST, instance=Product()) if get_system_setting('enable_jira'): jform = JIRAPKeyForm(request.POST, instance=JIRA_PKey()) else: jform = None if form.is_valid(): product = form.save() tags = request.POST.getlist('tags') t = ", ".join(tags) product.tags = t messages.add_message(request, messages.SUCCESS, 'Product added successfully.', extra_tags='alert-success') if get_system_setting('enable_jira'): if jform.is_valid(): jira_pkey = jform.save(commit=False) if jira_pkey.conf is not None: jira_pkey.product = product jira_pkey.save() messages.add_message(request, messages.SUCCESS, 'JIRA information added successfully.', extra_tags='alert-success') create_notification(event='product_added', title=product.name, url=request.build_absolute_uri(reverse('view_product', args=(product.id,)))) return HttpResponseRedirect(reverse('view_product', args=(product.id,))) else: form = ProductForm() if get_system_setting('enable_jira'): jform = JIRAPKeyForm() else: jform = None add_breadcrumb(title="New Product", top_level=False, request=request) return render(request, 'dojo/new_product.html', {'form': form, 'jform': jform})
def edit_engagement(request, eid): eng = Engagement.objects.get(pk=eid) jform = None if request.method == 'POST': form = EngForm2(request.POST, instance=eng) if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=True) if form.is_valid(): if 'jiraform-push_to_jira' in request.POST: try: jissue = JIRA_Issue.objects.get(engagement=eng) update_epic_task.delay(eng, jform.cleaned_data.get('push_to_jira')) enabled = True except: enabled = False add_epic_task.delay(eng, jform.cleaned_data.get('push_to_jira')) pass 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 = EngForm2(instance=eng) 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] add_breadcrumb(parent=eng, title="Edit Engagement", top_level=False, request=request) return render(request, 'dojo/new_eng.html', {'form': form, 'edit': True, 'jform': jform })
def close_eng(request, eid): eng = Engagement.objects.get(id=eid) eng.active = False eng.status = 'Completed' eng.updated = timezone.now() eng.save() if get_system_setting('enable_jira'): jpkey_set = JIRA_PKey.objects.filter(product=eng.product) if jpkey_set.count() >= 1: close_epic_task(eng, True) messages.add_message( request, messages.SUCCESS, 'Engagement closed successfully.', extra_tags='alert-success') if eng.engagement_type == 'CI/CD': return HttpResponseRedirect(reverse("view_engagements_cicd", args=(eng.product.id, ))) else: return HttpResponseRedirect(reverse("view_engagements", args=(eng.product.id, )))
def product_endpoint_report(request, pid): user = Dojo_User.objects.get(id=request.user.id) product = get_object_or_404(Product, id=pid) endpoints = Endpoint.objects.filter( product=product, finding__active=True, finding__verified=True, finding__false_p=False, finding__duplicate=False, finding__out_of_scope=False, ) ids = get_endpoint_ids(endpoints) endpoints = Endpoint.objects.filter(id__in=ids) endpoints = EndpointReportFilter(request.GET, queryset=endpoints) paged_endpoints = get_page_items(request, endpoints.qs, 25) 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 add_breadcrumb(parent=product, title="Vulnerable Product Endpoints Report", top_level=False, request=request) report_form = ReportOptionsForm() filename = "product_endpoint_report.pdf" template = "dojo/product_endpoint_pdf_report.html" report_name = "Product Endpoint Report: " + str(product) report_title = "Product Endpoint Report" report_subtitle = str(product) report_info = "Generated By %s on %s" % (user.get_full_name(), ( timezone.now().strftime("%m/%d/%Y %I:%M%p %Z"))) try: start_date = Finding.objects.filter( endpoints__in=endpoints.qs).order_by('date')[:1][0].date except: start_date = timezone.now() end_date = timezone.now() risk_acceptances = Risk_Acceptance.objects.filter( engagement__test__finding__endpoints__in=endpoints.qs) accepted_findings = [ finding for ra in risk_acceptances for finding in ra.accepted_findings.filter(endpoints__in=endpoints.qs) ] verified_findings = Finding.objects.filter( endpoints__in=endpoints.qs, date__range=[start_date, end_date], false_p=False, verified=True, duplicate=False, out_of_scope=False) open_findings = Finding.objects.filter(endpoints__in=endpoints.qs, false_p=False, verified=True, duplicate=False, out_of_scope=False, active=True, mitigated__isnull=True) closed_findings = Finding.objects.filter(endpoints__in=endpoints.qs, false_p=False, verified=True, duplicate=False, out_of_scope=False, mitigated__isnull=False) if generate: report_form = ReportOptionsForm(request.GET) if report_format == 'AsciiDoc': return render( request, 'dojo/asciidoc_report.html', { 'product_type': None, 'product': product, 'accepted_findings': accepted_findings, 'open_findings': open_findings, 'closed_findings': closed_findings, 'verified_findings': verified_findings, 'engagement': None, 'test': None, 'endpoints': endpoints, 'endpoint': None, 'findings': None, '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': request.user, 'title': 'Generate Report', }) elif report_format == 'PDF': endpoints = endpoints.qs.order_by('finding__numerical_severity') # lets create the report object and send it in to celery task 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: report = Report(name="Product Endpoints " + str(product), type="Product Endpoint", 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={ 'product': product, 'endpoints': endpoints, 'accepted_findings': accepted_findings, 'open_findings': open_findings, 'closed_findings': closed_findings, 'verified_findings': verified_findings, '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': get_system_setting('team_name'), 'title': 'Generate Report', 'host': report_url_resolver(request), 'user_id': request.user.id }, 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': None, 'product': product, 'engagement': None, 'test': None, 'endpoint': None, 'endpoints': endpoints.qs, 'findings': None, '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': request.user, 'title': 'Generate Report', }) else: raise Http404() product_tab = Product_Tab(product.id, "Product Endpoint Report", tab="endpoints") return render( request, 'dojo/request_endpoint_report.html', { "endpoints": paged_endpoints, "filtered": endpoints, "product_tab": product_tab, 'report_form': report_form, "name": "Vulnerable Product Endpoints", })
def process_jira_project_form(request, instance=None, product=None, engagement=None): if not get_system_setting('enable_jira'): return True, None error = False jira_project = None # supply empty instance to form so it has default values needed to make has_changed() work # jform = JIRAProjectForm(request.POST, instance=instance if instance else JIRA_Project(), product=product) jform = JIRAProjectForm(request.POST, instance=instance, product=product, engagement=engagement) # logging has_changed because it sometimes doesn't do what we expect logger.debug('jform has changed: %s', str(jform.has_changed())) if jform.has_changed(): # if no data was changed, no need to do anything! logger.debug('jform changed_data: %s', jform.changed_data) logger.debug('jform: %s', vars(jform)) if jform.is_valid(): try: jira_project = jform.save(commit=False) # could be a new jira_project, so set product_id if engagement: jira_project.engagement_id = engagement.id obj = engagement elif product: jira_project.product_id = product.id obj = product if not jira_project.product_id and not jira_project.engagement_id: raise ValueError('encountered JIRA_Project without product_id and without engagement_id') # only check jira project if form is sufficiently populated if jira_project.jira_instance and jira_project.project_key: # is_jira_project_valid already adds messages if not a valid jira project if not is_jira_project_valid(jira_project): logger.debug('unable to retrieve jira project from jira instance, invalid?!') error = True else: logger.debug(vars(jira_project)) jira_project.save() # update the in memory instance to make jira_project attribute work and it can be retrieved when pushing # an epic in the next step obj.jira_project = jira_project messages.add_message(request, messages.SUCCESS, 'JIRA Project config stored successfully.', extra_tags='alert-success') error = False logger.debug('stored JIRA_Project succesfully') except Exception as e: error = True logger.exception(e) pass else: logger.debug(jform.errors) error = True if error: messages.add_message(request, messages.ERROR, 'JIRA Project config not stored due to errors.', extra_tags='alert-danger') return not error, 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['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 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.set(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 product_endpoint_report(request, pid): user = Dojo_User.objects.get(id=request.user.id) product = get_object_or_404(Product.objects.all().prefetch_related('engagement_set__test_set__test_type', 'engagement_set__test_set__environment'), id=pid) endpoint_ids = Endpoint.objects.filter(product=product, finding__active=True, finding__verified=True, finding__false_p=False, finding__duplicate=False, finding__out_of_scope=False, ).values_list('id', flat=True) endpoints = prefetch_related_endpoints_for_report(Endpoint.objects.filter(id__in=endpoint_ids)) endpoints = EndpointReportFilter(request.GET, queryset=endpoints) paged_endpoints = get_page_items(request, endpoints.qs, 25) 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)) include_disclaimer = int(request.GET.get('include_disclaimer', 0)) disclaimer = get_system_setting('disclaimer') if include_disclaimer and len(disclaimer) == 0: disclaimer = 'Please configure in System Settings.' generate = "_generate" in request.GET add_breadcrumb(parent=product, title="Vulnerable Product Endpoints Report", top_level=False, request=request) report_form = ReportOptionsForm() template = "dojo/product_endpoint_pdf_report.html" report_name = "Product Endpoint Report: " + str(product) report_title = "Product Endpoint Report" report_subtitle = str(product) report_info = "Generated By %s on %s" % ( user.get_full_name(), (timezone.now().strftime("%m/%d/%Y %I:%M%p %Z"))) try: start_date = Finding.objects.filter(endpoints__in=endpoints.qs).order_by('date')[:1][0].date except: start_date = timezone.now() end_date = timezone.now() risk_acceptances = Risk_Acceptance.objects.filter(engagement__test__finding__endpoints__in=endpoints.qs) accepted_findings = [finding for ra in risk_acceptances for finding in ra.accepted_findings.filter(endpoints__in=endpoints.qs)] verified_findings = Finding.objects.filter(endpoints__in=endpoints.qs, date__range=[start_date, end_date], false_p=False, verified=True, duplicate=False, out_of_scope=False) open_findings = Finding.objects.filter(endpoints__in=endpoints.qs, false_p=False, verified=True, duplicate=False, out_of_scope=False, active=True, mitigated__isnull=True) closed_findings = Finding.objects.filter(endpoints__in=endpoints.qs, false_p=False, verified=True, duplicate=False, out_of_scope=False, mitigated__isnull=False) if generate: report_form = ReportOptionsForm(request.GET) if report_format == 'AsciiDoc': return render(request, 'dojo/asciidoc_report.html', {'product_type': None, 'product': product, 'accepted_findings': accepted_findings, 'open_findings': open_findings, 'closed_findings': closed_findings, 'verified_findings': verified_findings, 'engagement': None, 'test': None, 'endpoints': endpoints, 'endpoint': None, 'findings': None, '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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, 'user': request.user, 'title': 'Generate Report', }) elif report_format == 'HTML': return render(request, template, {'product_type': None, 'product': product, 'engagement': None, 'test': None, 'endpoint': None, 'endpoints': endpoints.qs, 'findings': None, '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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, 'user': request.user, 'title': 'Generate Report', }) else: raise Http404() product_tab = Product_Tab(product.id, "Product Endpoint Report", tab="endpoints") return render(request, 'dojo/request_endpoint_report.html', {"endpoints": paged_endpoints, "filtered": endpoints, "product_tab": product_tab, 'report_form': report_form, "name": "Vulnerable Product Endpoints", })
def webhook(request, secret=None): if not get_system_setting('enable_jira'): logger.debug('ignoring incoming webhook as JIRA is disabled.') raise Http404('JIRA disabled') elif not get_system_setting('enable_jira_web_hook'): logger.debug('ignoring incoming webhook as JIRA Webhook is disabled.') raise Http404('JIRA Webhook disabled') elif not get_system_setting('disable_jira_webhook_secret'): if not get_system_setting('jira_webhook_secret'): logger.warning( 'ignoring incoming webhook as JIRA Webhook secret is empty in Defect Dojo system settings.' ) raise PermissionDenied('JIRA Webhook secret cannot be empty') if secret != get_system_setting('jira_webhook_secret'): logger.warning('invalid secret provided to JIRA Webhook') raise PermissionDenied( 'invalid or no secret provided to JIRA Webhook') # if webhook secret is disabled in system_settings, we ignore the incoming secret, even if it doesn't match # example json bodies at the end of this file if request.content_type != 'application/json': return HttpResponseBadRequest("only application/json supported") if request.method == 'POST': try: parsed = json.loads(request.body.decode('utf-8')) if parsed.get('webhookEvent') == 'jira:issue_updated': # xml examples at the end of file jid = parsed['issue']['id'] jissue = get_object_or_404(JIRA_Issue, jira_id=jid) logging.info("Received issue update for {}".format( jissue.jira_key)) if jissue.finding: finding = jissue.finding assignee = parsed['issue']['fields'].get('assignee') assignee_name = assignee['name'] if assignee else None resolution = parsed['issue']['fields']['resolution'] # "resolution":{ # "self":"http://www.testjira.com/rest/api/2/resolution/11", # "id":"11", # "description":"Cancelled by the customer.", # "name":"Cancelled" # }, # or # "resolution": null # or # "resolution": "None" resolution = resolution if resolution and resolution != "None" else None resolution_id = resolution['id'] if resolution else None resolution_name = resolution['name'] if resolution else None jira_now = parse_datetime( parsed['issue']['fields']['updated']) jira_helper.process_resolution_from_jira( finding, resolution_id, resolution_name, assignee_name, jira_now) elif jissue.engagement: # if parsed['issue']['fields']['resolution'] != None: # eng.active = False # eng.status = 'Completed' # eng.save() return HttpResponse('Update for engagement ignored') else: raise Http404( 'No finding or engagement found for JIRA issue {}'. format(jissue.jira_key)) if parsed.get('webhookEvent') == 'comment_created': """ example incoming requests from JIRA Server 8.14.0 { "timestamp":1610269967824, "webhookEvent":"comment_created", "comment":{ "self":"https://jira.host.com/rest/api/2/issue/115254/comment/466578", "id":"466578", "author":{ "self":"https://jira.host.com/rest/api/2/user?username=defect.dojo", "name":"defect.dojo", "key":"defect.dojo", # seems to be only present on JIRA Server, not on Cloud "avatarUrls":{ "48x48":"https://www.gravatar.com/avatar/9637bfb970eff6176357df615f548f1c?d=mm&s=48", "24x24":"https://www.gravatar.com/avatar/9637bfb970eff6176357df615f548f1c?d=mm&s=24", "16x16":"https://www.gravatar.com/avatar9637bfb970eff6176357df615f548f1c?d=mm&s=16", "32x32":"https://www.gravatar.com/avatar/9637bfb970eff6176357df615f548f1c?d=mm&s=32" }, "displayName":"Defect Dojo", "active":true, "timeZone":"Europe/Amsterdam" }, "body":"(Valentijn Scholten):test4", "updateAuthor":{ "self":"https://jira.host.com/rest/api/2/user?username=defect.dojo", "name":"defect.dojo", "key":"defect.dojo", "avatarUrls":{ "48x48":"https://www.gravatar.com/avatar/9637bfb970eff6176357df615f548f1c?d=mm&s=48", "24x24""https://www.gravatar.com/avatar/9637bfb970eff6176357df615f548f1c?d=mm&s=24", "16x16":"https://www.gravatar.com/avatar/9637bfb970eff6176357df615f548f1c?d=mm&s=16", "32x32":"https://www.gravatar.com/avatar/9637bfb970eff6176357df615f548f1c?d=mm&s=32" }, "displayName":"Defect Dojo", "active":true, "timeZone":"Europe/Amsterdam" }, "created":"2021-01-10T10:12:47.824+0100", "updated":"2021-01-10T10:12:47.824+0100" } } """ comment_text = parsed['comment']['body'] commentor = '' if 'name' in parsed['comment']['updateAuthor']: commentor = parsed['comment']['updateAuthor']['name'] elif 'emailAddress' in parsed['comment']['updateAuthor']: commentor = parsed['comment']['updateAuthor'][ 'emailAddress'] else: logger.debug( 'Could not find the author of this jira comment!') commentor_display_name = parsed['comment']['updateAuthor'][ 'displayName'] # example: body['comment']['self'] = "http://www.testjira.com/jira_under_a_path/rest/api/2/issue/666/comment/456843" jid = parsed['comment']['self'].split('/')[-3] jissue = get_object_or_404(JIRA_Issue, jira_id=jid) logging.info("Received issue comment for {}".format( jissue.jira_key)) logger.debug('jissue: %s', vars(jissue)) if jissue.finding: # logger.debug('finding: %s', vars(jissue.finding)) jira_usernames = JIRA_Instance.objects.values_list( 'username', flat=True) for jira_userid in jira_usernames: # logger.debug('incoming username: %s jira config username: %s', commentor.lower(), jira_userid.lower()) if jira_userid.lower() == commentor.lower(): logger.debug( 'skipping incoming JIRA comment as the user id of the comment in JIRA (%s) matches the JIRA username in DefectDojo (%s)', commentor.lower(), jira_userid.lower()) return HttpResponse('') break finding = jissue.finding new_note = Notes() new_note.entry = '(%s (%s)): %s' % ( commentor_display_name, commentor, comment_text) new_note.author, created = User.objects.get_or_create( username='******') new_note.save() finding.notes.add(new_note) finding.jira_issue.jira_change = timezone.now() finding.jira_issue.save() finding.save() create_notification( event='other', title='JIRA incoming comment - %s' % (jissue.finding), url=reverse("view_finding", args=(jissue.finding.id, )), icon='check') elif jissue.engagement: return HttpResponse('Comment for engagement ignored') else: raise Http404( 'No finding or engagement found for JIRA issue {}'. format(jissue.jira_key)) if parsed.get('webhookEvent') not in [ 'comment_created', 'jira:issue_updated' ]: logger.info( 'Unrecognized JIRA webhook event received: {}'.format( parsed.get('webhookEvent'))) except Exception as e: if isinstance(e, Http404): logger.warning('404 error processing JIRA webhook') else: logger.exception(e) try: logger.debug('jira_webhook_body_parsed:') logger.debug(json.dumps(parsed, indent=4)) except: logger.debug('jira_webhook_body:') logger.debug(request.body.decode('utf-8')) # reraise to make sure we don't silently swallow things raise return HttpResponse('')
def metrics(request, mtype): template = 'dojo/metrics.html' page_name = 'Product Type Metrics' show_pt_filter = True findings = Finding.objects.filter( verified=True, severity__in=('Critical', 'High', 'Medium', 'Low', 'Info') ).prefetch_related( 'test__engagement__product', 'test__engagement__product__prod_type', 'test__engagement__risk_acceptance', 'risk_acceptance_set', 'reporter' ).extra(select={ 'ra_count': 'SELECT COUNT(*) FROM dojo_risk_acceptance INNER JOIN ' 'dojo_risk_acceptance_accepted_findings ON ' '( dojo_risk_acceptance.id = dojo_risk_acceptance_accepted_findings.risk_acceptance_id ) ' 'WHERE dojo_risk_acceptance_accepted_findings.finding_id = dojo_finding.id', }, ) active_findings = Finding.objects.filter( verified=True, active=True, severity__in=('Critical', 'High', 'Medium', 'Low', 'Info') ).prefetch_related( 'test__engagement__product', 'test__engagement__product__prod_type', 'test__engagement__risk_acceptance', 'risk_acceptance_set', 'reporter' ).extra(select={ 'ra_count': 'SELECT COUNT(*) FROM dojo_risk_acceptance INNER JOIN ' 'dojo_risk_acceptance_accepted_findings ON ' '( dojo_risk_acceptance.id = dojo_risk_acceptance_accepted_findings.risk_acceptance_id ) ' 'WHERE dojo_risk_acceptance_accepted_findings.finding_id = dojo_finding.id', }, ) if mtype != 'All': pt = Product_Type.objects.filter(id=mtype) request.GET._mutable = True request.GET.appendlist('test__engagement__product__prod_type', mtype) request.GET._mutable = False mtype = pt[0].name show_pt_filter = False page_name = '%s Metrics' % mtype prod_type = pt elif 'test__engagement__product__prod_type' in request.GET: prod_type = Product_Type.objects.filter(id__in=request.GET.getlist( 'test__engagement__product__prod_type', [])) else: prod_type = Product_Type.objects.all() findings = MetricsFindingFilter(request.GET, queryset=findings) active_findings = MetricsFindingFilter(request.GET, queryset=active_findings) findings.qs # this is needed to load details from filter since it is lazy active_findings.qs # this is needed to load details from filter since it is lazy start_date = findings.filters['date'].start_date start_date = datetime(start_date.year, start_date.month, start_date.day, tzinfo=timezone.get_current_timezone()) end_date = findings.filters['date'].end_date end_date = datetime(end_date.year, end_date.month, end_date.day, tzinfo=timezone.get_current_timezone()) if len(prod_type) > 0: findings_closed = Finding.objects.filter( mitigated__range=[start_date, end_date], test__engagement__product__prod_type__in=prod_type ).prefetch_related('test__engagement__product') # capture the accepted findings in period accepted_findings = Finding.objects.filter(risk_acceptance__created__range=[start_date, end_date], test__engagement__product__prod_type__in=prod_type). \ prefetch_related('test__engagement__product') accepted_findings_counts = Finding.objects.filter(risk_acceptance__created__range=[start_date, end_date], test__engagement__product__prod_type__in=prod_type). \ prefetch_related('test__engagement__product').aggregate( total=Sum( Case(When(severity__in=('Critical', 'High', 'Medium', 'Low'), then=Value(1)), output_field=IntegerField())), critical=Sum( Case(When(severity='Critical', then=Value(1)), output_field=IntegerField())), high=Sum( Case(When(severity='High', then=Value(1)), output_field=IntegerField())), medium=Sum( Case(When(severity='Medium', then=Value(1)), output_field=IntegerField())), low=Sum( Case(When(severity='Low', then=Value(1)), output_field=IntegerField())), info=Sum( Case(When(severity='Info', then=Value(1)), output_field=IntegerField())), ) else: findings_closed = Finding.objects.filter( mitigated__range=[start_date, end_date]).prefetch_related( 'test__engagement__product') accepted_findings = Finding.objects.filter(risk_acceptance__created__range=[start_date, end_date]). \ prefetch_related('test__engagement__product') accepted_findings_counts = Finding.objects.filter(risk_acceptance__created__range=[start_date, end_date]). \ prefetch_related('test__engagement__product').aggregate( total=Sum( Case(When(severity__in=('Critical', 'High', 'Medium', 'Low'), then=Value(1)), output_field=IntegerField())), critical=Sum( Case(When(severity='Critical', then=Value(1)), output_field=IntegerField())), high=Sum( Case(When(severity='High', then=Value(1)), output_field=IntegerField())), medium=Sum( Case(When(severity='Medium', then=Value(1)), output_field=IntegerField())), low=Sum( Case(When(severity='Low', then=Value(1)), output_field=IntegerField())), info=Sum( Case(When(severity='Info', then=Value(1)), output_field=IntegerField())), ) r = relativedelta(end_date, start_date) months_between = (r.years * 12) + r.months # include current month months_between += 1 weeks_between = int( ceil((((r.years * 12) + r.months) * 4.33) + (r.days / 7))) if weeks_between <= 0: weeks_between += 2 monthly_counts = get_period_counts(active_findings.qs, findings.qs, findings_closed, accepted_findings, months_between, start_date, relative_delta='months') weekly_counts = get_period_counts(active_findings.qs, findings.qs, findings_closed, accepted_findings, weeks_between, start_date, relative_delta='weeks') top_ten = Product.objects.filter( engagement__test__finding__verified=True, engagement__test__finding__false_p=False, engagement__test__finding__duplicate=False, engagement__test__finding__out_of_scope=False, engagement__test__finding__mitigated__isnull=True, engagement__test__finding__severity__in=('Critical', 'High', 'Medium', 'Low'), prod_type__in=prod_type).annotate( critical=Sum( Case(When(engagement__test__finding__severity='Critical', then=Value(1)), output_field=IntegerField())), high=Sum( Case(When(engagement__test__finding__severity='High', then=Value(1)), output_field=IntegerField())), medium=Sum( Case(When(engagement__test__finding__severity='Medium', then=Value(1)), output_field=IntegerField())), low=Sum( Case(When(engagement__test__finding__severity='Low', then=Value(1)), output_field=IntegerField())), total=Sum( Case(When(engagement__test__finding__severity__in=('Critical', 'High', 'Medium', 'Low'), then=Value(1)), output_field=IntegerField()))).order_by( '-critical', '-high', '-medium', '-low')[:10] age_detail = [0, 0, 0, 0] in_period_counts = { "Critical": 0, "High": 0, "Medium": 0, "Low": 0, "Info": 0, "Total": 0 } in_period_details = {} closed_in_period_counts = { "Critical": 0, "High": 0, "Medium": 0, "Low": 0, "Info": 0, "Total": 0 } closed_in_period_details = {} accepted_in_period_details = {} for finding in findings.qs: if 0 <= finding.age <= 30: age_detail[0] += 1 elif 30 < finding.age <= 60: age_detail[1] += 1 elif 60 < finding.age <= 90: age_detail[2] += 1 elif finding.age > 90: age_detail[3] += 1 in_period_counts[finding.severity] += 1 in_period_counts['Total'] += 1 if finding.test.engagement.product.name not in in_period_details: in_period_details[finding.test.engagement.product.name] = { 'path': reverse('view_product_findings', args=(finding.test.engagement.product.id, )), 'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0, 'Info': 0, 'Total': 0 } in_period_details[finding.test.engagement.product.name][ finding.severity] += 1 in_period_details[finding.test.engagement.product.name]['Total'] += 1 for finding in accepted_findings: if finding.test.engagement.product.name not in accepted_in_period_details: accepted_in_period_details[ finding.test.engagement.product.name] = { 'path': reverse('accepted_findings') + '?test__engagement__product=' + str(finding.test.engagement.product.id), 'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0, 'Info': 0, 'Total': 0 } accepted_in_period_details[finding.test.engagement.product.name][ finding.severity] += 1 accepted_in_period_details[ finding.test.engagement.product.name]['Total'] += 1 for f in findings_closed: closed_in_period_counts[f.severity] += 1 closed_in_period_counts['Total'] += 1 if f.test.engagement.product.name not in closed_in_period_details: closed_in_period_details[f.test.engagement.product.name] = { 'path': reverse('closed_findings') + '?test__engagement__product=' + str(f.test.engagement.product.id), 'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0, 'Info': 0, 'Total': 0 } closed_in_period_details[f.test.engagement.product.name][ f.severity] += 1 closed_in_period_details[f.test.engagement.product.name]['Total'] += 1 punchcard = list() ticks = list() highest_count = 0 if 'view' in request.GET and 'dashboard' == request.GET['view']: punchcard, ticks, highest_count = get_punchcard_data( findings.qs, weeks_between, start_date) page_name = (get_system_setting('team_name')) + " Metrics" template = 'dojo/dashboard-metrics.html' add_breadcrumb(title=page_name, top_level=not len(request.GET), request=request) return render( request, template, { 'name': page_name, 'start_date': start_date, 'end_date': end_date, 'findings': findings, 'opened_per_month': monthly_counts['opened_per_period'], 'active_per_month': monthly_counts['active_per_period'], 'opened_per_week': weekly_counts['opened_per_period'], 'accepted_per_month': monthly_counts['accepted_per_period'], 'accepted_per_week': weekly_counts['accepted_per_period'], 'top_ten_products': top_ten, 'age_detail': age_detail, 'in_period_counts': in_period_counts, 'in_period_details': in_period_details, 'accepted_in_period_counts': accepted_findings_counts, 'accepted_in_period_details': accepted_in_period_details, 'closed_in_period_counts': closed_in_period_counts, 'closed_in_period_details': closed_in_period_details, 'punchcard': punchcard, 'ticks': ticks, 'highest_count': highest_count, 'show_pt_filter': show_pt_filter, })
class OpenFindingFilter(DojoFilter): title = CharFilter(lookup_expr='icontains') duplicate = ReportBooleanFilter() # sourcefile = CharFilter(lookup_expr='icontains') sourcefilepath = CharFilter(lookup_expr='icontains') param = CharFilter(lookup_expr='icontains') payload = CharFilter(lookup_expr='icontains') date = DateRangeFilter() last_reviewed = DateRangeFilter() cwe = MultipleChoiceFilter(choices=[]) severity = MultipleChoiceFilter(choices=SEVERITY_CHOICES) test__test_type = ModelMultipleChoiceFilter( queryset=Test_Type.objects.all()) test__engagement__product = ModelMultipleChoiceFilter( queryset=Product.objects.all(), label="Product") test__engagement__risk_acceptance = ReportRiskAcceptanceFilter( label="Risk Accepted") if get_system_setting('enable_jira'): jira_issue = BooleanFilter(field_name='jira_issue', lookup_expr='isnull', exclude=True, label='JIRA issue') o = OrderingFilter( # tuple-mapping retains order fields=( ('numerical_severity', 'numerical_severity'), ('date', 'date'), ('last_reviewed', 'last_reviewed'), ('title', 'title'), ('test__engagement__product__name', 'test__engagement__product__name'), ), ) class Meta: model = Finding exclude = [ 'url', 'description', 'mitigation', 'impact', 'endpoint', 'references', 'test', 'is_template', 'thread_id', 'notes', 'scanner_confidence', 'mitigated', 'numerical_severity', 'reporter', 'last_reviewed', 'line', 'duplicate_finding', 'hash_code', 'images', 'line_number', 'reviewers', 'mitigated_by', 'sourcefile', 'jira_creation', 'jira_change', 'created' ] def __init__(self, *args, **kwargs): self.user = None self.pid = None if 'user' in kwargs: self.user = kwargs.pop('user') if 'pid' in kwargs: self.pid = kwargs.pop('pid') super(OpenFindingFilter, self).__init__(*args, **kwargs) cwe = dict() cwe = dict( [cwe, cwe] for cwe in self.queryset.values_list('cwe', flat=True).distinct() if type(cwe) is int and cwe is not None and cwe > 0) cwe = collections.OrderedDict(sorted(cwe.items())) self.form.fields['cwe'].choices = list(cwe.items()) if self.user is not None and not self.user.is_staff: if self.form.fields.get('test__engagement__product'): qs = Product.objects.filter(authorized_users__in=[self.user]) self.form.fields['test__engagement__product'].queryset = qs self.form.fields['endpoints'].queryset = Endpoint.objects.filter( product__authorized_users__in=[self.user]).distinct() # Don't show the product filter on the product finding view if self.pid: del self.form.fields['test__engagement__product']
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, })
# if public=False, includes only endpoints the current user has access to public=True, # The API of a OpenSource project should be public accessible permission_classes=[permissions.AllowAny], ) urlpatterns = [ # These are the SAML2 related URLs. You can change "^saml2_auth/" regex to # any path you want, like "^sso_auth/", "^sso_login/", etc. (required) url(r'^saml2/', include('django_saml2_auth.urls')), # The following line will replace the default user login with SAML2 (optional) # If you want to specific the after-login-redirect-URL, use parameter "?next=/the/path/you/want" # with this view. url(r'^saml2/login/$', django_saml2_auth.views.signin), # tastypie api url(r'^%sapi/' % get_system_setting('url_prefix'), include(v1_api.urls)), # Django Rest Framework API v2 url(r'^%sapi/v2/' % get_system_setting('url_prefix'), include(v2_api.urls)), # api doc urls url(r'%sapi/v1/doc/' % get_system_setting('url_prefix'), include((swagger_urls, 'tp_s'), namespace='tastypie_swagger'), kwargs={ "tastypie_api_module": "dojo.urls.v1_api", "namespace": "tastypie_swagger", "version": "1.0"}), # action history url(r'^%shistory/(?P<cid>\d+)/(?P<oid>\d+)$' % get_system_setting('url_prefix'), views.action_history, name='action_history'), url(r'^%s' % get_system_setting('url_prefix'), include(ur)), url(r'^%sapi/v2/api-token-auth/' % get_system_setting('url_prefix'), tokenviews.obtain_auth_token), url(r'^%sapi/v2/doc/' % get_system_setting('url_prefix'), schema_view.with_ui('swagger', cache_timeout=0), name='api_v2_schema'),
ur += notifications_urls from tastypie_swagger.views import SwaggerView, ResourcesView, SchemaView swagger_urls = [ url(r'^$', SwaggerView.as_view(), name='index'), url(r'^resources/$', ResourcesView.as_view(), name='resources'), url(r'^schema/(?P<resource>\S+)$', SchemaView.as_view()), url(r'^schema/$', SchemaView.as_view(), name='schema'), ] urlpatterns = [ # django admin url(r'^%sadmin/' % get_system_setting('url_prefix'), include(admin.site.urls)), # tastypie api url(r'^%sapi/' % get_system_setting('url_prefix'), include(v1_api.urls)), # api doc urls url(r'%sapi/v1/doc/' % get_system_setting('url_prefix'), include(swagger_urls, namespace='tastypie_swagger'), kwargs={ "tastypie_api_module": "dojo.urls.v1_api", "namespace": "tastypie_swagger", "version": "1.0"}), # action history url(r'^%shistory/(?P<cid>\d+)/(?P<oid>\d+)$' % get_system_setting('url_prefix'), views.action_history, name='action_history'), url(r'^%s' % get_system_setting('url_prefix'), include(ur)), ]
def promote_to_finding(request, fid): finding = get_object_or_404(Stub_Finding, id=fid) test = finding.test form_error = False jira_available = False if get_system_setting('enable_jira') and JIRA_PKey.objects.filter(product=test.engagement.product) != 0: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues) jira_available = True else: jform = None form = PromoteFindingForm(initial={'title': finding.title, 'date': finding.date, 'severity': finding.severity, 'description': finding.description, 'test': finding.test, 'reporter': finding.reporter}) if request.method == 'POST': form = PromoteFindingForm(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.active = True new_finding.false_p = False new_finding.duplicate = False new_finding.mitigated = None new_finding.verified = True new_finding.out_of_scope = False new_finding.save() new_finding.endpoints = form.cleaned_data['endpoints'] new_finding.save() finding.delete() if 'jiraform' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues) if jform.is_valid(): add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira')) messages.add_message(request, messages.SUCCESS, 'Finding promoted successfully.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_test', 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') add_breadcrumb(parent=test, title="Promote Finding", top_level=False, request=request) return render(request, 'dojo/promote_to_finding.html', {'form': form, 'test': test, 'stub_finding': finding, 'form_error': form_error, })
def edit_finding(request, fid): finding = get_object_or_404(Finding, id=fid) old_status = finding.status() form = FindingForm(instance=finding) form.initial['tags'] = [tag.name for tag in finding.tags] form_error = False jform = None try: jissue = JIRA_Issue.objects.get(finding=finding) enabled = True except: enabled = False pass if get_system_setting('enable_jira') and JIRA_PKey.objects.filter(product=finding.test.engagement.product) != 0: jform = JIRAFindingForm(enabled=enabled, prefix='jiraform') if request.method == 'POST': form = FindingForm(request.POST, instance=finding) if form.is_valid(): new_finding = form.save(commit=False) new_finding.test = finding.test 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 if new_finding.active is True: new_finding.false_p = False new_finding.mitigated = None new_finding.mitigated_by = None 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.endpoints = form.cleaned_data['endpoints'] new_finding.last_reviewed = timezone.now() new_finding.last_reviewed_by = request.user tags = request.POST.getlist('tags') t = ", ".join(tags) new_finding.tags = t new_finding.save() if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=enabled) if jform.is_valid(): try: jissue = JIRA_Issue.objects.get(finding=new_finding) update_issue_task.delay(new_finding, old_status, jform.cleaned_data.get('push_to_jira')) except: add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira')) pass tags = request.POST.getlist('tags') t = ", ".join(tags) new_finding.tags = t messages.add_message(request, messages.SUCCESS, 'Finding saved 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_finding', args=(new_finding.id,))) else: messages.add_message(request, messages.ERROR, 'There appears to be errors on the form, please correct below.', extra_tags='alert-danger') form_error = True if form_error and 'endpoints' in form.cleaned_data: form.fields['endpoints'].queryset = form.cleaned_data['endpoints'] else: form.fields['endpoints'].queryset = finding.endpoints.all() form.initial['tags'] = [tag.name for tag in finding.tags] add_breadcrumb(parent=finding, title="Edit", top_level=False, request=request) return render(request, 'dojo/edit_findings.html', {'form': form, 'finding': finding, 'jform' : jform })
def send_slack_notification(event, user=None, *args, **kwargs): from dojo.utils import get_system_setting def _post_slack_message(channel): res = requests.request(method='POST', url='https://slack.com/api/chat.postMessage', data={ 'token': get_system_setting('slack_token'), 'channel': channel, 'username': get_system_setting('slack_username'), 'text': create_notification_message( event, user, 'slack', *args, **kwargs) }) if 'error' in res.text: logger.error("Slack is complaining. See raw text below.") logger.error(res.text) raise RuntimeError('Error posting message to Slack: ' + res.text) try: # If the user has slack information on profile and chooses to receive slack notifications # Will receive a DM if user is not None: logger.debug('personal notification to slack for user %s', user) if hasattr(user, 'usercontactinfo' ) and user.usercontactinfo.slack_username is not None: slack_user_id = user.usercontactinfo.slack_user_id if not slack_user_id: # Lookup the slack userid the first time, then save it. slack_user_id = get_slack_user_id( user.usercontactinfo.slack_username) if slack_user_id: slack_user_save = UserContactInfo.objects.get( user_id=user.id) slack_user_save.slack_user_id = slack_user_id slack_user_save.save() # only send notification if we managed to find the slack_user_id if slack_user_id: channel = '@{}'.format(slack_user_id) _post_slack_message(channel) else: logger.info( "The user %s does not have a email address informed for Slack in profile.", user) else: # System scope slack notifications, and not personal would still see this go through if get_system_setting('slack_channel') is not None: channel = get_system_setting('slack_channel') logger.info( "Sending system notification to system channel {}.".format( channel)) _post_slack_message(channel) else: logger.debug( 'slack_channel not configured: skipping system notification' ) except Exception as e: logger.exception(e) log_alert(e, 'Slack Notification', title=kwargs['title'], description=str(e), url=kwargs['url'])
def fetch_system_setting(name): return get_system_setting(name)
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 edit_product(request, pid): prod = Product.objects.get(pk=pid) system_settings = System_Settings.objects.get() jira_enabled = system_settings.enable_jira jira_inst = None jform = None try: jira_inst = JIRA_PKey.objects.get(product=prod) except: jira_inst = None pass if request.method == 'POST': form = ProductForm(request.POST, instance=prod) if form.is_valid(): form.save() tags = request.POST.getlist('tags') t = ", ".join(tags) prod.tags = t messages.add_message(request, messages.SUCCESS, 'Product updated successfully.', extra_tags='alert-success') if get_system_setting('enable_jira') and jira_inst: jform = JIRAPKeyForm(request.POST, instance=jira_inst) # need to handle delete try: jform.save() except: pass elif get_system_setting('enable_jira'): jform = JIRAPKeyForm(request.POST) if jform.is_valid(): new_conf = jform.save(commit=False) new_conf.product_id = pid new_conf.save() messages.add_message(request, messages.SUCCESS, 'JIRA information updated successfully.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_product', args=(pid,))) else: form = ProductForm(instance=prod, initial={'auth_users': prod.authorized_users.all(), 'tags': get_tag_list(Tag.objects.get_for_object(prod))}) if jira_enabled and (jira_inst is not None): if jira_inst is not None: jform = JIRAPKeyForm(instance=jira_inst) else: jform = JIRAPKeyForm() elif jira_enabled: jform = JIRAPKeyForm() else: jform = None form.initial['tags'] = [tag.name for tag in prod.tags] product_tab = Product_Tab(pid, title="Edit Product", tab="settings") return render(request, 'dojo/edit_product.html', {'form': form, 'product_tab': product_tab, 'jform': jform, 'product': prod })
ur += object_urls from tastypie_swagger.views import SwaggerView, ResourcesView, SchemaView swagger_urls = [ url(r'^$', SwaggerView.as_view(), name='index'), url(r'^resources/$', ResourcesView.as_view(), name='resources'), url(r'^schema/(?P<resource>\S+)$', SchemaView.as_view()), url(r'^schema/$', SchemaView.as_view(), name='schema'), ] urlpatterns = [ # django admin url(r'^%sadmin/' % get_system_setting('url_prefix'), include(admin.site.urls)), # tastypie api url(r'^%sapi/' % get_system_setting('url_prefix'), include(v1_api.urls)), # api doc urls url(r'%sapi/v1/doc/' % get_system_setting('url_prefix'), include(swagger_urls, namespace='tastypie_swagger'), kwargs={ "tastypie_api_module": "dojo.urls.v1_api", "namespace": "tastypie_swagger", "version": "1.0"}), # action history url(r'^%shistory/(?P<cid>\d+)/(?P<oid>\d+)$' % get_system_setting('url_prefix'), views.action_history, name='action_history'), url(r'^%s' % get_system_setting('url_prefix'), include(ur)), ]
ur += tool_product_urls ur += cred_urls ur += system_settings_urls from tastypie_swagger.views import SwaggerView, ResourcesView, SchemaView swagger_urls = [ url(r'^$', SwaggerView.as_view(), name='index'), url(r'^resources/$', ResourcesView.as_view(), name='resources'), url(r'^schema/(?P<resource>\S+)$', SchemaView.as_view()), url(r'^schema/$', SchemaView.as_view(), name='schema'), ] urlpatterns = [ # django admin url(r'^%sadmin/' % get_system_setting('url_prefix'), include(admin.site.urls)), # tastypie api url(r'^%sapi/' % get_system_setting('url_prefix'), include(v1_api.urls)), # api doc urls url(r'%sapi/v1/doc/' % get_system_setting('url_prefix'), include(swagger_urls, namespace='tastypie_swagger'), kwargs={ "tastypie_api_module": "dojo.urls.v1_api", "namespace": "tastypie_swagger", "version": "1.0" }), # action history url(r'^%shistory/(?P<cid>\d+)/(?P<oid>\d+)$' % get_system_setting('url_prefix'), views.action_history,
def edit_product(request, pid): prod = Product.objects.get(pk=pid) system_settings = System_Settings.objects.get() jira_enabled = system_settings.enable_jira jira_inst = None jform = None sonarqube_form = None try: jira_inst = JIRA_PKey.objects.get(product=prod) except: jira_inst = None pass sonarqube_conf = Sonarqube_Product.objects.filter(product=prod).first() if request.method == 'POST': form = ProductForm(request.POST, instance=prod) if form.is_valid(): form.save() tags = request.POST.getlist('tags') t = ", ".join('"{0}"'.format(w) for w in tags) prod.tags = t messages.add_message(request, messages.SUCCESS, 'Product updated successfully.', extra_tags='alert-success') if get_system_setting('enable_jira') and jira_inst: jform = JIRAPKeyForm(request.POST, instance=jira_inst) # need to handle delete try: jform.save() except: pass elif get_system_setting('enable_jira'): jform = JIRAPKeyForm(request.POST) if jform.is_valid(): new_conf = jform.save(commit=False) new_conf.product_id = pid new_conf.save() messages.add_message( request, messages.SUCCESS, 'JIRA information updated successfully.', extra_tags='alert-success') # SonarQube API Configuration sonarqube_form = Sonarqube_ProductForm(request.POST, instance=sonarqube_conf) if sonarqube_form.is_valid(): new_conf = sonarqube_form.save(commit=False) new_conf.product_id = pid new_conf.save() return HttpResponseRedirect(reverse('view_product', args=(pid, ))) else: form = ProductForm(instance=prod, initial={ 'auth_users': prod.authorized_users.all(), 'tags': get_tag_list(Tag.objects.get_for_object(prod)) }) if jira_enabled and (jira_inst is not None): if jira_inst is not None: jform = JIRAPKeyForm(instance=jira_inst) else: jform = JIRAPKeyForm() elif jira_enabled: jform = JIRAPKeyForm() else: jform = None sonarqube_form = Sonarqube_ProductForm(instance=sonarqube_conf) form.initial['tags'] = [tag.name for tag in prod.tags] product_tab = Product_Tab(pid, title="Edit Product", tab="settings") return render( request, 'dojo/edit_product.html', { 'form': form, 'product_tab': product_tab, 'jform': jform, 'sonarqube_form': sonarqube_form, 'product': prod })
def webhook(request): # Webhook shouldn't be active if jira isn't enabled if not get_system_setting('enable_jira'): raise PermissionDenied elif not get_system_setting('enable_jira_web_hook'): raise PermissionDenied if request.method == 'POST': parsed = json.loads(request.body.decode('utf-8')) if parsed.get('webhookEvent') == 'jira:issue_updated': jid = parsed['issue']['id'] jissue = get_object_or_404(JIRA_Issue, jira_id=jid) if jissue.finding is not None: finding = jissue.finding jira_conf = finding.jira_conf() resolved = True resolution = parsed['issue']['fields']['resolution'] if resolution is None: resolved = False if finding.active == resolved: if finding.active: if jira_conf and resolution['name'] in jira_conf.accepted_resolutions: finding.active = False finding.mitigated = None finding.is_Mitigated = False finding.false_p = False assignee = parsed['issue']['fields'].get('assignee') assignee_name = assignee['name'] if assignee else None Risk_Acceptance.objects.create( accepted_by=assignee_name, reporter=finding.reporter, ).accepted_findings.set([finding]) elif jira_conf and resolution['name'] in jira_conf.false_positive_resolutions: finding.active = False finding.verified = False finding.mitigated = None finding.is_Mitigated = False finding.false_p = True finding.remove_from_any_risk_acceptance() else: # Mitigated by default as before now = timezone.now() finding.active = False finding.mitigated = now finding.endpoints.clear() finding.false_p = False finding.remove_from_any_risk_acceptance() else: # Reopen / Open Jira issue finding.active = True finding.mitigated = None finding.is_Mitigated = False finding.false_p = False finding.remove_from_any_risk_acceptance() finding.jira_change = timezone.now() finding.save() """ if jissue.engagement is not None: eng = jissue.engagement if parsed['issue']['fields']['resolution'] != None: eng.active = False eng.status = 'Completed' eng.save() """ if parsed.get('webhookEvent') == 'comment_created': comment_text = parsed['comment']['body'] commentor = parsed['comment']['updateAuthor']['displayName'] jid = parsed['comment']['self'].split('/')[7] jissue = JIRA_Issue.objects.get(jira_id=jid) finding = jissue.finding new_note = Notes() new_note.entry = '(%s): %s' % (commentor, comment_text) new_note.author, created = User.objects.get_or_create(username='******') new_note.save() finding.notes.add(new_note) finding.jira_change = timezone.now() finding.save() if parsed.get('webhookEvent') not in ['comment_created', 'jira:issue_updated']: logger.info('Unrecognized JIRA webhook event received: {}'.format(parsed.get('webhookEvent'))) return HttpResponse('')
def is_jira_enabled(): if not get_system_setting('enable_jira'): logger.debug('JIRA is disabled, not doing anything') return False return True
from pytz import timezone from dojo.celery import app from dojo.endpoint.views import get_endpoint_ids from dojo.filters import ReportFindingFilter, ReportAuthedFindingFilter, EndpointReportFilter, ReportFilter, \ EndpointFilter from dojo.forms import ReportOptionsForm, DeleteReportForm from dojo.models import Product_Type, Finding, Product, Engagement, Test, \ Dojo_User, Endpoint, Report, Risk_Acceptance from dojo.reports.widgets import CoverPage, PageBreak, TableOfContents, WYSIWYGContent, FindingList, EndpointList, \ CustomReportJsonForm, ReportOptions, report_widget_factory from dojo.tasks import async_pdf_report, async_custom_pdf_report from dojo.utils import get_page_items, add_breadcrumb, get_period_counts, get_system_setting from dojo.utils import get_period_counts_legacy localtz = timezone(get_system_setting('time_zone')) logging.basicConfig( level=logging.DEBUG, format='[%(asctime)s] %(levelname)s [%(name)s:%(lineno)d] %(message)s', datefmt='%d/%b/%Y %H:%M:%S', filename=settings.DOJO_ROOT + '/../django_app.log', ) logger = logging.getLogger(__name__) def report_url_resolver(request): try: url_resolver = request.META[ 'HTTP_X_FORWARDED_PROTO'] + "://" + request.META[ 'HTTP_X_FORWARDED_FOR']
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.product_id = form.cleaned_data.get('product').id temp_form.save() tags = request.POST.getlist('tags') t = ", ".join('"{0}"'.format(w) for w in 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(initial={'product': eng.product.id}, 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 new_eng_for_app(request, pid, cicd=False): jform = None prod = Product.objects.get(id=pid) if request.method == 'POST': form = EngForm(request.POST, cicd=cicd) if form.is_valid(): new_eng = form.save(commit=False) if not new_eng.name: new_eng.name = str(new_eng.target_start) new_eng.threat_model = False new_eng.api_test = False new_eng.pen_test = False new_eng.check_list = False new_eng.product_id = form.cleaned_data.get('product').id if new_eng.threat_model: new_eng.progress = 'threat_model' else: new_eng.progress = 'other' if cicd: new_eng.engagement_type = 'CI/CD' new_eng.status = "In Progress" new_eng.save() tags = request.POST.getlist('tags') t = ", ".join('"{0}"'.format(w) for w in tags) new_eng.tags = t if get_system_setting('enable_jira'): # Test to make sure there is a Jira project associated the product try: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=JIRA_PKey.objects.get( product=prod).push_all_issues) if jform.is_valid(): add_epic_task.delay( new_eng, jform.cleaned_data.get('push_to_jira')) except JIRA_PKey.DoesNotExist: pass messages.add_message(request, messages.SUCCESS, 'Engagement added successfully.', extra_tags='alert-success') create_notification(event='engagement_added', title=new_eng.name + " for " + prod.name, engagement=new_eng, url=reverse('view_engagement', args=(new_eng.id, )), objowner=new_eng.lead) if "_Add Tests" in request.POST: return HttpResponseRedirect( reverse('add_tests', args=(new_eng.id, ))) elif "_Import Scan Results" in request.POST: return HttpResponseRedirect( reverse('import_scan_results', args=(new_eng.id, ))) else: return HttpResponseRedirect( reverse('view_engagement', args=(new_eng.id, ))) else: form = EngForm(initial={ 'lead': request.user, 'target_start': timezone.now().date(), 'target_end': timezone.now().date() + timedelta(days=7), 'product': prod.id }, cicd=cicd, product=prod.id) if (get_system_setting('enable_jira')): if JIRA_PKey.objects.filter(product=prod).count() != 0: jform = JIRAFindingForm(prefix='jiraform', enabled=JIRA_PKey.objects.get( product=prod).push_all_issues) product_tab = Product_Tab(pid, title="New Engagement", tab="engagements") return render(request, 'dojo/new_eng.html', { 'form': form, 'pid': pid, 'product_tab': product_tab, 'jform': jform })
def edit_finding(request, fid): finding = get_object_or_404(Finding, id=fid) old_status = finding.status() form = FindingForm(instance=finding) form.initial['tags'] = [tag.name for tag in finding.tags] form_error = False jform = None try: jissue = JIRA_Issue.objects.get(finding=finding) enabled = True except: enabled = False pass if get_system_setting('enable_jira') and JIRA_PKey.objects.filter(product=finding.test.engagement.product) != 0: jform = JIRAFindingForm(enabled=enabled, prefix='jiraform') if request.method == 'POST': form = FindingForm(request.POST, instance=finding) if form.is_valid(): new_finding = form.save(commit=False) new_finding.test = finding.test 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 if new_finding.active is True: new_finding.false_p = False new_finding.mitigated = None new_finding.mitigated_by = None 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.endpoints = form.cleaned_data['endpoints'] new_finding.last_reviewed = timezone.now() new_finding.last_reviewed_by = request.user tags = request.POST.getlist('tags') t = ", ".join(tags) new_finding.tags = t new_finding.save() if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=enabled) if jform.is_valid(): try: jissue = JIRA_Issue.objects.get(finding=new_finding) update_issue_task.delay(new_finding, old_status, jform.cleaned_data.get('push_to_jira')) except: add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira')) pass tags = request.POST.getlist('tags') t = ", ".join(tags) new_finding.tags = t messages.add_message(request, messages.SUCCESS, 'Finding saved 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_finding', args=(new_finding.id,))) else: messages.add_message(request, messages.ERROR, 'There appears to be errors on the form, please correct below.', extra_tags='alert-danger') form_error = True if form_error and 'endpoints' in form.cleaned_data: form.fields['endpoints'].queryset = form.cleaned_data['endpoints'] else: form.fields['endpoints'].queryset = finding.endpoints.all() form.initial['tags'] = [tag.name for tag in finding.tags] add_breadcrumb(parent=finding, title="Edit", top_level=False, request=request) return render(request, 'dojo/edit_findings.html', {'form': form, 'finding': finding, 'jform' : jform })
def edit_engagement(request, eid): engagement = Engagement.objects.get(pk=eid) is_ci_cd = engagement.engagement_type == "CI/CD" 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.id, 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 else: engagement.active = True engagement.save() tags = request.POST.getlist('tags') t = ", ".join('"{0}"'.format(w) for w in tags) engagement.tags = t 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, engagement=engagement) 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) form = EngForm(initial={'product': engagement.product}, instance=engagement, cicd=is_ci_cd, product=engagement.product, user=request.user) jira_project_form = None 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) form.initial['tags'] = [tag.name for tag in engagement.tags] title = ' CI/CD' if is_ci_cd else '' product_tab = Product_Tab(engagement.product.id, title="Edit" + title + " Engagement", tab="engagements") product_tab.setEngagement(engagement) return render( request, 'dojo/new_eng.html', { 'product_tab': product_tab, 'form': form, 'edit': True, 'jira_epic_form': jira_epic_form, 'jira_project_form': jira_project_form, 'engagement': engagement, })
schema_view = get_schema_view( openapi.Info( title="Defect Dojo API", default_version='v2', description="To use the API you need be authorized.", ), # if public=False, includes only endpoints the current user has access to public=True, # The API of a OpenSource project should be public accessible permission_classes=[permissions.AllowAny], ) urlpatterns = [ # Django Rest Framework API v2 url(r'^%sapi/v2/' % get_system_setting('url_prefix'), include(v2_api.urls)), # action history url(r'^%shistory/(?P<cid>\d+)/(?P<oid>\d+)$' % get_system_setting('url_prefix'), views.action_history, name='action_history'), url(r'^%s' % get_system_setting('url_prefix'), include(ur)), url(r'^%sapi/v2/api-token-auth/' % get_system_setting('url_prefix'), tokenviews.obtain_auth_token, name='api-token-auth'), url(r'^%sapi/v2/user_profile/' % get_system_setting('url_prefix'), UserProfileView.as_view(), name='user_profile'), # drf-yasg = OpenAPI2
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 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_Type": if settings.FEATURE_AUTHORIZATION_V2: user_has_permission_or_403(request.user, obj, Permissions.Product_Type_View) else: if not (request.user.is_staff or check_auth_users_list(request.user, obj)): raise PermissionDenied elif type(obj).__name__ == "Product": if settings.FEATURE_AUTHORIZATION_V2: user_has_permission_or_403(request.user, obj, Permissions.Product_View) else: if not (request.user.is_staff or check_auth_users_list(request.user, obj)): raise PermissionDenied elif type(obj).__name__ == "Engagement": if settings.FEATURE_AUTHORIZATION_V2: user_has_permission_or_403(request.user, obj, Permissions.Engagement_View) else: if not (request.user.is_staff or check_auth_users_list(request.user, obj)): raise PermissionDenied elif type(obj).__name__ == "Test": if settings.FEATURE_AUTHORIZATION_V2: user_has_permission_or_403(request.user, obj, Permissions.Test_View) else: if not (request.user.is_staff or check_auth_users_list(request.user, obj)): raise PermissionDenied elif type(obj).__name__ == "Endpoint": if settings.FEATURE_AUTHORIZATION_V2: user_has_permission_or_403(request.user, obj, Permissions.Endpoint_View) else: if not (request.user.is_staff or check_auth_users_list(request.user, obj)): 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)) include_disclaimer = int(request.GET.get('include_disclaimer', 0)) disclaimer = get_system_setting('disclaimer') if include_disclaimer and len(disclaimer) == 0: disclaimer = 'Please configure in System Settings.' generate = "_generate" in request.GET host_view = "host_view" 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 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.distinct().order_by('numerical_severity'), 'findings': findings.qs.distinct().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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, '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 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() endpoints = Endpoint.objects.filter(product=product).distinct() context = {'product': product, 'engagements': engagements, 'tests': tests, 'report_name': report_name, 'findings': findings.qs.distinct().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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, '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) 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() endpoints = Endpoint.objects.filter(product=engagement.product).distinct() context = {'engagement': engagement, 'tests': tests, 'report_name': report_name, 'findings': findings.qs.distinct().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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, '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))) 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.distinct().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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, '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 if host_view: report_name = "Endpoint Host Report: " + endpoint.host endpoints = Endpoint.objects.filter(host=endpoint.host, product=endpoint.product).distinct() report_title = "Endpoint Host Report" report_subtitle = endpoint.host else: report_name = "Endpoint Report: " + str(endpoint) endpoints = Endpoint.objects.filter(pk=endpoint.id).distinct() report_title = "Endpoint Report" report_subtitle = str(endpoint) report_type = "Endpoint" template = 'dojo/endpoint_pdf_report.html' 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.distinct().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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, '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 = ReportFindingFilter(request.GET, queryset=prefetch_related_findings_for_report(obj).distinct()) report_name = 'Finding' report_type = 'Finding' template = 'dojo/finding_pdf_report.html' report_title = "Finding Report" report_subtitle = '' context = {'findings': findings.qs.distinct().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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, '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.distinct().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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, 'user': user, 'team_name': settings.TEAM_NAME, 'title': report_title, 'user_id': request.user.id, 'host': report_url_resolver(request), 'host_view': host_view, 'context': context, }) 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.distinct().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, 'include_disclaimer': include_disclaimer, 'disclaimer': disclaimer, 'user': user, 'team_name': settings.TEAM_NAME, 'title': report_title, 'user_id': request.user.id, 'host': "", 'host_view': host_view, 'context': context, }) else: raise Http404() paged_findings = get_page_items(request, findings.qs.distinct().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: if host_view: product_tab = Product_Tab(endpoint.product.id, title="Endpoint Host Report", tab="endpoints") else: 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, 'host_view': host_view, 'context': context, })
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() 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=True) 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 add_breadcrumb(parent=test, title="Add Finding", top_level=False, request=request) return render(request, 'dojo/add_findings.html', {'form': form, 'jform': jform, 'findings': findings, 'temp': True, 'fid': finding.id, 'tid': test.id, 'test': test, })
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": # 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 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, 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': report_title, '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': 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, 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': 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=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': report_title, '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': 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 metrics(request, mtype): template = 'dojo/metrics.html' page_name = 'Product Type Metrics' show_pt_filter = True findings = Finding.objects.filter(verified=True, severity__in=('Critical', 'High', 'Medium', 'Low', 'Info')).prefetch_related( 'test__engagement__product', 'test__engagement__product__prod_type', 'test__engagement__risk_acceptance', 'risk_acceptance_set', 'reporter').extra( select={ 'ra_count': 'SELECT COUNT(*) FROM dojo_risk_acceptance INNER JOIN ' 'dojo_risk_acceptance_accepted_findings ON ' '( dojo_risk_acceptance.id = dojo_risk_acceptance_accepted_findings.risk_acceptance_id ) ' 'WHERE dojo_risk_acceptance_accepted_findings.finding_id = dojo_finding.id', }, ) active_findings = Finding.objects.filter(verified=True, active=True, severity__in=('Critical', 'High', 'Medium', 'Low', 'Info')).prefetch_related( 'test__engagement__product', 'test__engagement__product__prod_type', 'test__engagement__risk_acceptance', 'risk_acceptance_set', 'reporter').extra( select={ 'ra_count': 'SELECT COUNT(*) FROM dojo_risk_acceptance INNER JOIN ' 'dojo_risk_acceptance_accepted_findings ON ' '( dojo_risk_acceptance.id = dojo_risk_acceptance_accepted_findings.risk_acceptance_id ) ' 'WHERE dojo_risk_acceptance_accepted_findings.finding_id = dojo_finding.id', }, ) if mtype != 'All': pt = Product_Type.objects.filter(id=mtype) request.GET._mutable = True request.GET.appendlist('test__engagement__product__prod_type', mtype) request.GET._mutable = False mtype = pt[0].name show_pt_filter = False page_name = '%s Metrics' % mtype prod_type = pt elif 'test__engagement__product__prod_type' in request.GET: prod_type = Product_Type.objects.filter(id__in=request.GET.getlist('test__engagement__product__prod_type', [])) else: prod_type = Product_Type.objects.all() findings = MetricsFindingFilter(request.GET, queryset=findings) active_findings = MetricsFindingFilter(request.GET, queryset=active_findings) findings.qs # this is needed to load details from filter since it is lazy active_findings.qs # this is needed to load details from filter since it is lazy start_date = findings.filters['date'].start_date start_date = datetime(start_date.year, start_date.month, start_date.day, tzinfo=timezone.get_current_timezone()) end_date = findings.filters['date'].end_date end_date = datetime(end_date.year, end_date.month, end_date.day, tzinfo=timezone.get_current_timezone()) if len(prod_type) > 0: findings_closed = Finding.objects.filter(mitigated__range=[start_date, end_date], test__engagement__product__prod_type__in=prod_type).prefetch_related( 'test__engagement__product') # capture the accepted findings in period accepted_findings = Finding.objects.filter(risk_acceptance__created__range=[start_date, end_date], test__engagement__product__prod_type__in=prod_type). \ prefetch_related('test__engagement__product') accepted_findings_counts = Finding.objects.filter(risk_acceptance__created__range=[start_date, end_date], test__engagement__product__prod_type__in=prod_type). \ prefetch_related('test__engagement__product').aggregate( total=Sum( Case(When(severity__in=('Critical', 'High', 'Medium', 'Low'), then=Value(1)), output_field=IntegerField())), critical=Sum( Case(When(severity='Critical', then=Value(1)), output_field=IntegerField())), high=Sum( Case(When(severity='High', then=Value(1)), output_field=IntegerField())), medium=Sum( Case(When(severity='Medium', then=Value(1)), output_field=IntegerField())), low=Sum( Case(When(severity='Low', then=Value(1)), output_field=IntegerField())), info=Sum( Case(When(severity='Info', then=Value(1)), output_field=IntegerField())), ) else: findings_closed = Finding.objects.filter(mitigated__range=[start_date, end_date]).prefetch_related( 'test__engagement__product') accepted_findings = Finding.objects.filter(risk_acceptance__created__range=[start_date, end_date]). \ prefetch_related('test__engagement__product') accepted_findings_counts = Finding.objects.filter(risk_acceptance__created__range=[start_date, end_date]). \ prefetch_related('test__engagement__product').aggregate( total=Sum( Case(When(severity__in=('Critical', 'High', 'Medium', 'Low'), then=Value(1)), output_field=IntegerField())), critical=Sum( Case(When(severity='Critical', then=Value(1)), output_field=IntegerField())), high=Sum( Case(When(severity='High', then=Value(1)), output_field=IntegerField())), medium=Sum( Case(When(severity='Medium', then=Value(1)), output_field=IntegerField())), low=Sum( Case(When(severity='Low', then=Value(1)), output_field=IntegerField())), info=Sum( Case(When(severity='Info', then=Value(1)), output_field=IntegerField())), ) r = relativedelta(end_date, start_date) months_between = (r.years * 12) + r.months # include current month months_between += 1 weeks_between = int(ceil((((r.years * 12) + r.months) * 4.33) + (r.days / 7))) if weeks_between <= 0: weeks_between += 2 monthly_counts = get_period_counts(active_findings.qs, findings.qs, findings_closed, accepted_findings, months_between, start_date, relative_delta='months') weekly_counts = get_period_counts(active_findings.qs, findings.qs, findings_closed, accepted_findings, weeks_between, start_date, relative_delta='weeks') top_ten = Product.objects.filter(engagement__test__finding__verified=True, engagement__test__finding__false_p=False, engagement__test__finding__duplicate=False, engagement__test__finding__out_of_scope=False, engagement__test__finding__mitigated__isnull=True, engagement__test__finding__severity__in=( 'Critical', 'High', 'Medium', 'Low'), prod_type__in=prod_type).annotate( critical=Sum( Case(When(engagement__test__finding__severity='Critical', then=Value(1)), output_field=IntegerField()) ), high=Sum( Case(When(engagement__test__finding__severity='High', then=Value(1)), output_field=IntegerField()) ), medium=Sum( Case(When(engagement__test__finding__severity='Medium', then=Value(1)), output_field=IntegerField()) ), low=Sum( Case(When(engagement__test__finding__severity='Low', then=Value(1)), output_field=IntegerField()) ), total=Sum( Case(When(engagement__test__finding__severity__in=( 'Critical', 'High', 'Medium', 'Low'), then=Value(1)), output_field=IntegerField())) ).order_by('-critical', '-high', '-medium', '-low')[:10] age_detail = [0, 0, 0, 0] in_period_counts = {"Critical": 0, "High": 0, "Medium": 0, "Low": 0, "Info": 0, "Total": 0} in_period_details = {} closed_in_period_counts = {"Critical": 0, "High": 0, "Medium": 0, "Low": 0, "Info": 0, "Total": 0} closed_in_period_details = {} accepted_in_period_details = {} for finding in findings.qs: if 0 <= finding.age <= 30: age_detail[0] += 1 elif 30 < finding.age <= 60: age_detail[1] += 1 elif 60 < finding.age <= 90: age_detail[2] += 1 elif finding.age > 90: age_detail[3] += 1 in_period_counts[finding.severity] += 1 in_period_counts['Total'] += 1 if finding.test.engagement.product.name not in in_period_details: in_period_details[finding.test.engagement.product.name] = { 'path': reverse('view_product_findings', args=(finding.test.engagement.product.id,)), 'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0, 'Info': 0, 'Total': 0} in_period_details[ finding.test.engagement.product.name ][finding.severity] += 1 in_period_details[finding.test.engagement.product.name]['Total'] += 1 for finding in accepted_findings: if finding.test.engagement.product.name not in accepted_in_period_details: accepted_in_period_details[finding.test.engagement.product.name] = { 'path': reverse('accepted_findings') + '?test__engagement__product=' + str( finding.test.engagement.product.id), 'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0, 'Info': 0, 'Total': 0} accepted_in_period_details[ finding.test.engagement.product.name ][finding.severity] += 1 accepted_in_period_details[finding.test.engagement.product.name]['Total'] += 1 for f in findings_closed: closed_in_period_counts[f.severity] += 1 closed_in_period_counts['Total'] += 1 if f.test.engagement.product.name not in closed_in_period_details: closed_in_period_details[f.test.engagement.product.name] = { 'path': reverse('closed_findings') + '?test__engagement__product=' + str( f.test.engagement.product.id), 'Critical': 0, 'High': 0, 'Medium': 0, 'Low': 0, 'Info': 0, 'Total': 0} closed_in_period_details[ f.test.engagement.product.name ][f.severity] += 1 closed_in_period_details[f.test.engagement.product.name]['Total'] += 1 punchcard = list() ticks = list() highest_count = 0 if 'view' in request.GET and 'dashboard' == request.GET['view']: punchcard, ticks, highest_count = get_punchcard_data(findings.qs, weeks_between, start_date) page_name = (get_system_setting('team_name')) + " Metrics" template = 'dojo/dashboard-metrics.html' add_breadcrumb(title=page_name, top_level=not len(request.GET), request=request) return render(request, template, { 'name': page_name, 'start_date': start_date, 'end_date': end_date, 'findings': findings, 'opened_per_month': monthly_counts['opened_per_period'], 'active_per_month': monthly_counts['active_per_period'], 'opened_per_week': weekly_counts['opened_per_period'], 'accepted_per_month': monthly_counts['accepted_per_period'], 'accepted_per_week': weekly_counts['accepted_per_period'], 'top_ten_products': top_ten, 'age_detail': age_detail, 'in_period_counts': in_period_counts, 'in_period_details': in_period_details, 'accepted_in_period_counts': accepted_findings_counts, 'accepted_in_period_details': accepted_in_period_details, 'closed_in_period_counts': closed_in_period_counts, 'closed_in_period_details': closed_in_period_details, 'punchcard': punchcard, 'ticks': ticks, 'highest_count': highest_count, 'show_pt_filter': show_pt_filter, })
def process_request(self, request): timezone.activate(get_system_setting('time_zone'))
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, ObjectDoesNotExist): raise Http404() product_id = None active_tab = None finding = None test = False object_value = None if ct.model == "product": user_has_permission_or_403(request.user, obj, Permissions.Product_View) product_id = obj.id active_tab = "overview" object_value = Product.objects.get(id=obj.id) elif ct.model == "engagement": user_has_permission_or_403(request.user, obj, Permissions.Engagement_View) object_value = Engagement.objects.get(id=obj.id) product_id = object_value.product.id active_tab = "engagements" elif ct.model == "test": user_has_permission_or_403(request.user, obj, Permissions.Test_View) object_value = Test.objects.get(id=obj.id) product_id = object_value.engagement.product.id active_tab = "engagements" test = True elif ct.model == "finding": user_has_permission_or_403(request.user, obj, Permissions.Finding_View) object_value = Finding.objects.get(id=obj.id) product_id = object_value.test.engagement.product.id active_tab = "findings" finding = object_value elif ct.model == "endpoint": user_has_permission_or_403(request.user, obj, Permissions.Endpoint_View) object_value = Endpoint.objects.get(id=obj.id) product_id = object_value.product.id active_tab = "endpoints" elif ct.model == "risk_acceptance": engagements = Engagement.objects.filter(risk_acceptance=obj) authorized = False for engagement in engagements: if user_has_permission(request.user, engagement, Permissions.Engagement_View): authorized = True break if not authorized: raise PermissionDenied elif ct.model == "user": user_has_configuration_permission_or_403(request.user, 'auth.view_user', legacy='superuser') else: if not request.user.is_superuser: raise PermissionDenied 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) if not get_system_setting('enable_auditlog'): messages.add_message( request, messages.WARNING, 'Audit logging is currently disabled in System Settings.', extra_tags='alert-danger') 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 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 = datetime.now(tz=localtz) 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() 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=True) 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': datetime.now(tz=localtz).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 add_breadcrumb(parent=test, title="Add Finding", top_level=False, request=request) return render(request, 'dojo/add_findings.html', {'form': form, 'jform': jform, 'findings': findings, 'temp': True, 'fid': finding.id, 'tid': test.id, 'test': test, })
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('engagment_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 promote_to_finding(request, fid): finding = get_object_or_404(Stub_Finding, id=fid) test = finding.test form_error = False jira_available = False if get_system_setting('enable_jira') and JIRA_PKey.objects.filter(product=test.engagement.product) != 0: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues) jira_available = True else: jform = None form = PromoteFindingForm(initial={'title': finding.title, 'date': finding.date, 'severity': finding.severity, 'description': finding.description, 'test': finding.test, 'reporter': finding.reporter}) if request.method == 'POST': form = PromoteFindingForm(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.active = True new_finding.false_p = False new_finding.duplicate = False new_finding.mitigated = None new_finding.verified = True new_finding.out_of_scope = False new_finding.save() new_finding.endpoints = form.cleaned_data['endpoints'] new_finding.save() finding.delete() if 'jiraform' in request.POST: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues) if jform.is_valid(): add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira')) messages.add_message(request, messages.SUCCESS, 'Finding promoted successfully.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_test', 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') add_breadcrumb(parent=test, title="Promote Finding", top_level=False, request=request) return render(request, 'dojo/promote_to_finding.html', {'form': form, 'test': test, 'stub_finding': finding, 'form_error': form_error, })
def product_endpoint_report(request, pid): user = Dojo_User.objects.get(id=request.user.id) product = get_object_or_404(Product, id=pid) endpoints = Endpoint.objects.filter(product=product, finding__active=True, finding__verified=True, finding__false_p=False, finding__duplicate=False, finding__out_of_scope=False, ) ids = get_endpoint_ids(endpoints) endpoints = Endpoint.objects.filter(id__in=ids) if request.user.is_staff or request.user in product.authorized_users.all(): pass # user is authorized for this product else: raise PermissionDenied endpoints = EndpointReportFilter(request.GET, queryset=endpoints) paged_endpoints = get_page_items(request, endpoints.qs, 25) 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 add_breadcrumb(parent=product, title="Vulnerable Product Endpoints Report", top_level=False, request=request) report_form = ReportOptionsForm() filename = "product_endpoint_report.pdf" template = "dojo/product_endpoint_pdf_report.html" report_name = "Product Endpoint Report: " + str(product) report_title = "Product Endpoint Report" report_subtitle = str(product) report_info = "Generated By %s on %s" % ( user.get_full_name(), (timezone.now().strftime("%m/%d/%Y %I:%M%p %Z"))) try: start_date = Finding.objects.filter(endpoints__in=endpoints.qs).order_by('date')[:1][0].date except: start_date = timezone.now() end_date = timezone.now() risk_acceptances = Risk_Acceptance.objects.filter(engagement__test__finding__endpoints__in=endpoints.qs) accepted_findings = [finding for ra in risk_acceptances for finding in ra.accepted_findings.filter(endpoints__in=endpoints.qs)] verified_findings = Finding.objects.filter(endpoints__in=endpoints.qs, date__range=[start_date, end_date], false_p=False, verified=True, duplicate=False, out_of_scope=False) open_findings = Finding.objects.filter(endpoints__in=endpoints.qs, false_p=False, verified=True, duplicate=False, out_of_scope=False, active=True, mitigated__isnull=True) closed_findings = Finding.objects.filter(endpoints__in=endpoints.qs, false_p=False, verified=True, duplicate=False, out_of_scope=False, mitigated__isnull=False) if generate: report_form = ReportOptionsForm(request.GET) if report_format == 'AsciiDoc': return render(request, 'dojo/asciidoc_report.html', {'product_type': None, 'product': product, 'accepted_findings': accepted_findings, 'open_findings': open_findings, 'closed_findings': closed_findings, 'verified_findings': verified_findings, 'engagement': None, 'test': None, 'endpoints': endpoints, 'endpoint': None, 'findings': None, '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': request.user, 'title': 'Generate Report', }) elif report_format == 'PDF': endpoints = endpoints.qs.order_by('finding__numerical_severity') # lets create the report object and send it in to celery task 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: report = Report(name="Product Endpoints " + str(product), type="Product Endpoint", 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={'product': product, 'endpoints': endpoints, 'accepted_findings': accepted_findings, 'open_findings': open_findings, 'closed_findings': closed_findings, 'verified_findings': verified_findings, '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': get_system_setting('team_name'), 'title': 'Generate Report', 'host': report_url_resolver(request), 'user_id': request.user.id}, 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')) else: raise Http404() product_tab = Product_Tab(product.id, "Product Endpoint Report", tab="endpoints") return render(request, 'dojo/request_endpoint_report.html', {"endpoints": paged_endpoints, "filtered": endpoints, "product_tab": product_tab, 'report_form': report_form, "name": "Vulnerable Product Endpoints", })
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.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') add_breadcrumb(parent=test, title="Add Finding", top_level=False, request=request) return render(request, 'dojo/add_findings.html', {'form': form, 'test': test, 'temp': False, 'tid': tid, 'form_error': form_error, 'jform': jform, })
def edit_product(request, pid): prod = Product.objects.get(pk=pid) jira_enabled = True jira_inst = None jform = None try: jira_inst = JIRA_PKey.objects.get(product=prod) except: jira_enabled = False pass if request.method == 'POST': form = ProductForm(request.POST, instance=prod) if form.is_valid(): form.save() tags = request.POST.getlist('tags') t = ", ".join(tags) prod.tags = t messages.add_message(request, messages.SUCCESS, 'Product updated successfully.', extra_tags='alert-success') if get_system_setting('enable_jira') and jira_enabled: jform = JIRAPKeyForm(request.POST, instance=jira_inst) #need to handle delete try: jform.save() except: pass else: jform = JIRAPKeyForm(request.POST) if jform.is_valid(): new_conf = jform.save(commit=False) new_conf.product_id = pid new_conf.save() messages.add_message( request, messages.SUCCESS, 'JIRA information updated successfully.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_product', args=(pid, ))) else: form = ProductForm(instance=prod, initial={ 'auth_users': prod.authorized_users.all(), 'tags': get_tag_list(Tag.objects.get_for_object(prod)) }) if get_system_setting('enable_jira') and jira_enabled: if jira_enabled: jform = JIRAPKeyForm(instance=jira_inst) else: jform = JIRAPKeyForm() else: jform = None add_breadcrumb(parent=prod, title="Edit", top_level=False, request=request) return render(request, 'dojo/edit_product.html', { 'form': form, 'jform': jform, 'product': prod, })
def new_eng_for_app(request, pid): jform = None prod = Product.objects.get(id=pid) if request.method == 'POST': form = EngForm(request.POST) if form.is_valid(): new_eng = form.save(commit=False) new_eng.product = prod if new_eng.threat_model: new_eng.progress = 'threat_model' else: new_eng.progress = 'other' new_eng.save() if get_system_setting('enable_jira'): #Test to make sure there is a Jira project associated the product try: jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=JIRA_PKey.objects.get( product=prod).push_all_issues) if jform.is_valid(): add_epic_task.delay( new_eng, jform.cleaned_data.get('push_to_jira')) except JIRA_PKey.DoesNotExist: pass #else: # print >>sys.stderr, 'no prefix is found' messages.add_message(request, messages.SUCCESS, 'Engagement added successfully.', extra_tags='alert-success') create_notification(event='engagement_added', title='Engagement added', engagement=new_eng, url=request.build_absolute_uri( reverse('view_engagement', args=(new_eng.id, ))), objowner=new_eng.lead) if "_Add Tests" in request.POST: return HttpResponseRedirect( reverse('add_tests', args=(new_eng.id, ))) else: return HttpResponseRedirect( reverse('view_engagement', args=(new_eng.id, ))) else: form = EngForm(initial={}) if (get_system_setting('enable_jira')): if JIRA_PKey.objects.filter(product=prod).count() != 0: jform = JIRAFindingForm(prefix='jiraform', enabled=JIRA_PKey.objects.get( product=prod).push_all_issues) add_breadcrumb(parent=prod, title="New Engagement", top_level=False, request=request) return render(request, 'dojo/new_eng.html', { 'form': form, 'pid': pid, 'jform': jform })
def add_findings(request, tid): test = Test.objects.get(id=tid) form_error = False enabled = False jform = None form = AddFindingForm(initial={'date': datetime.now(tz=localtz).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.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 = datetime.now(tz=localtz) 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') add_breadcrumb(parent=test, title="Add Finding", top_level=False, request=request) return render(request, 'dojo/add_findings.html', {'form': form, 'test': test, 'temp': False, 'tid': tid, 'form_error': form_error, 'jform': jform, })
from auditlog.models import LogEntry from django import forms from django.contrib.auth.models import User from django.utils import six from django.utils.translation import ugettext_lazy as _ from django_filters import FilterSet, CharFilter, OrderingFilter, \ ModelMultipleChoiceFilter, ModelChoiceFilter, MultipleChoiceFilter, \ BooleanFilter from django_filters.filters import ChoiceFilter, _truncate, DateTimeFilter from pytz import timezone from dojo.models import Dojo_User, Product_Type, Finding, Product, Test_Type, \ Endpoint, Development_Environment, Finding_Template, Report from dojo.utils import get_system_setting local_tz = timezone(get_system_setting('time_zone')) SEVERITY_CHOICES = (('Info', 'Info'), ('Low', 'Low'), ('Medium', 'Medium'), ('High', 'High'), ('Critical', 'Critical')) BOOLEAN_CHOICES = (('false', 'No'), ('true', 'Yes'),) EARLIEST_FINDING = None def now(): return local_tz.localize(datetime.today()) def get_earliest_finding(): global EARLIEST_FINDING if EARLIEST_FINDING is not None:
def fetch_system_setting(name): return get_system_setting(name)