def update_epic(engagement): logger.debug('trying to update jira EPIC for %d:%s', engagement.id, engagement.name) if not is_jira_configured_and_enabled(engagement): return False logger.debug('config found') jira_project = get_jira_project(engagement) jira_instance = get_jira_instance(engagement) if jira_project.enable_engagement_epic_mapping: try: jira = get_jira_connection(jira_instance) j_issue = get_jira_issue(engagement) issue = jira.issue(j_issue.jira_id) issue.update(summary=engagement.name, description=engagement.name) return True except JIRAError as e: logger.exception(e) log_jira_generic_alert('Jira Engagement/Epic Update Error', str(e)) return False else: add_error_message_to_response( 'Push to JIRA for Epic skipped because enable_engagement_epic_mapping is not checked for this engagement' ) return False
def import_endpoint_meta(request, pid): product = get_object_or_404(Product, id=pid) form = ImportEndpointMetaForm() if request.method == 'POST': form = ImportEndpointMetaForm(request.POST, request.FILES) if form.is_valid(): file = request.FILES.get('file', None) # Make sure size is not too large if file and is_scan_file_too_large(file): messages.add_message( request, messages.ERROR, "Report file is too large. Maximum supported size is {} MB".format(settings.SCAN_FILE_MAX_SIZE), extra_tags='alert-danger') create_endpoints = form.cleaned_data['create_endpoints'] create_tags = form.cleaned_data['create_tags'] create_dojo_meta = form.cleaned_data['create_dojo_meta'] try: endpoint_meta_import(file, product, create_endpoints, create_tags, create_dojo_meta, origin='UI', request=request) except Exception as e: logger.exception(e) add_error_message_to_response('An exception error occurred during the report import:%s' % str(e)) return HttpResponseRedirect(reverse('endpoint') + "?product=" + pid) add_breadcrumb(title="Endpoint Meta Importer", top_level=False, request=request) product_tab = Product_Tab(product.id, title="Endpoint Meta Importer", tab="endpoints") return render(request, 'dojo/endpoint_meta_importer.html', { 'product_tab': product_tab, 'form': form, })
def get_jira_connection_raw(jira_server, jira_username, jira_password): try: jira = JIRA(server=jira_server, basic_auth=(jira_username, jira_password), options={"verify": settings.JIRA_SSL_VERIFY}, max_retries=0) logger.debug('logged in to JIRA ' '%s' ' successfully', jira_server) return jira except JIRAError as e: logger.exception(e) if e.status_code in [401, 403]: log_jira_generic_alert('JIRA Authentication Error', e) else: log_jira_generic_alert('Unknown JIRA Connection Error', e) add_error_message_to_response( 'Unable to authenticate to JIRA. Please check the URL, username, password, captcha challenge, Network connection. Details in alert on top right. ' + str(e)) raise e except requests.exceptions.RequestException as re: logger.exception(re) log_jira_generic_alert('Unknown JIRA Connection Error', re) add_error_message_to_response( 'Unable to authenticate to JIRA. Please check the URL, username, password, captcha challenge, Network connection. Details in alert on top right. ' + str(re)) raise re
def add_epic(engagement): logger.debug('trying to create a new jira EPIC for %d:%s', engagement.id, engagement.name) if not is_jira_configured_and_enabled(engagement): return False logger.debug('config found') jira_project = get_jira_project(engagement) jira_instance = get_jira_instance(engagement) if jira_project.enable_engagement_epic_mapping: issue_dict = { 'project': { 'key': jira_project.project_key }, 'summary': engagement.name, 'description': engagement.name, 'issuetype': { 'name': 'Epic' }, get_epic_name_field_name(jira_instance): engagement.name, } try: jira = get_jira_connection(jira_instance) logger.debug('add_epic: %s', issue_dict) new_issue = jira.create_issue(fields=issue_dict) j_issue = JIRA_Issue(jira_id=new_issue.id, jira_key=new_issue.key, engagement=engagement, jira_project=jira_project) j_issue.save() return True except JIRAError as e: # should we try to parse the errors as JIRA is very strange in how it responds. # for example a non existent project_key leads to "project key is required" which sounds like something is missing # but it's just a non-existent project (or maybe a project for which the account has no create permission?) # # {"errorMessages":[],"errors":{"project":"project is required"}} logger.exception(e) error = str(e) message = "" if "customfield" in error: message = "The 'Epic name id' in your DefectDojo Jira Configuration does not appear to be correct. Please visit, " + jira_instance.url + \ "/rest/api/2/field and search for Epic Name. Copy the number out of cf[number] and place in your DefectDojo settings for Jira and try again. For example, if your results are cf[100001] then copy 100001 and place it in 'Epic name id'. (Your Epic Id will be different.) \n\n" log_jira_generic_alert('Jira Engagement/Epic Creation Error', message + error) return False else: add_error_message_to_response( 'Push to JIRA for Epic skipped because enable_engagement_epic_mapping is not checked for this engagement' ) return False
def get_jira_meta(jira, jira_project): meta = jira.createmeta( projectKeys=jira_project.project_key, issuetypeNames=jira_project.jira_instance.default_issue_type, expand="projects.issuetypes.fields") meta_data_error = False if len(meta['projects']) == 0: # non-existent project, or no permissions # [09/Nov/2020 21:04:22] DEBUG [dojo.jira_link.helper:595] get_jira_meta: { # "expand": "projects", # "projects": [] # } meta_data_error = True message = 'unable to retrieve metadata from JIRA %s for project %s. Invalid project key or no permissions to this project?' % ( jira_project.jira_instance, jira_project.project_key) elif len(meta['projects'][0]['issuetypes']) == 0: # default issue type doesn't exist in project # [09/Nov/2020 21:09:03] DEBUG [dojo.jira_link.helper:595] get_jira_meta: { # "expand": "projects", # "projects": [ # { # "expand": "issuetypes", # "self": "https://jira-uat.com/rest/api/2/project/1212", # "id": "1212", # "key": "ISO", # "name": "ISO ISMS", # "avatarUrls": { # "48x48": "https://jira-uat.com/secure/projectavatar?pid=14431&avatarId=17200", # "24x24": "https://jira-uat.com/secure/projectavatar?size=small&pid=14431&avatarId=17200", # "16x16": "https://jira-uat.com/secure/projectavatar?size=xsmall&pid=14431&avatarId=17200", # "32x32": "https://jira-uat.com/secure/projectavatar?size=medium&pid=14431&avatarId=17200" # }, # "issuetypes": [] # } # ] # } meta_data_error = True message = 'unable to retrieve metadata from JIRA %s for issuetype %s in project %s. Invalid default issue type configured in Defect Dojo?' % ( jira_project.jira_instance, jira_project.jira_instance.default_issue_type, jira_project.project_key) if meta_data_error: logger.warn(message) logger.warn("get_jira_meta: %s", json.dumps(meta, indent=4)) # this is None safe add_error_message_to_response(message) raise JIRAError(text=message) else: return meta
def close_epic(eng, push_to_jira): engagement = eng if not is_jira_enabled(): return False if not is_jira_configured_and_enabled(engagement): return False jira_project = get_jira_project(engagement) jira_instance = get_jira_instance(engagement) if jira_project.enable_engagement_epic_mapping: if push_to_jira: try: jissue = get_jira_issue(eng) if jissue is None: logger.warn("JIRA close epic failed: no issue found") return False req_url = jira_instance.url + '/rest/api/latest/issue/' + \ jissue.jira_id + '/transitions' json_data = { 'transition': { 'id': jira_instance.close_status_key } } r = requests.post(url=req_url, auth=HTTPBasicAuth(jira_instance.username, jira_instance.password), json=json_data) if r.status_code != 204: logger.warn("JIRA close epic failed with error: {}".format( r.text)) return False return True except JIRAError as e: logger.exception(e) log_jira_generic_alert('Jira Engagement/Epic Close Error', str(e)) return False else: add_error_message_to_response( 'Push to JIRA for Epic skipped because enable_engagement_epic_mapping is not checked for this engagement' ) return False
def delete_jira(request, tid): jira_instance = get_object_or_404(JIRA_Instance, pk=tid) # eng = test.engagement # TODO Make Form form = DeleteJIRAInstanceForm(instance=jira_instance) if request.method == 'POST': if 'id' in request.POST and str( jira_instance.id) == request.POST['id']: form = DeleteJIRAInstanceForm(request.POST, instance=jira_instance) if form.is_valid(): try: jira_instance.delete() messages.add_message( request, messages.SUCCESS, 'JIRA Conf and relationships removed.', extra_tags='alert-success') create_notification( event='other', title='Deletion of JIRA: %s' % jira_instance.configuration_name, description='JIRA "%s" was deleted by %s' % (jira_instance.configuration_name, request.user), url=request.build_absolute_uri(reverse('jira')), ) return HttpResponseRedirect(reverse('jira')) except Exception as e: add_error_message_to_response( 'Unable to delete JIRA Instance, probably because it is used by JIRA Issues: %s' % str(e)) collector = NestedObjects(using=DEFAULT_DB_ALIAS) collector.collect([jira_instance]) rels = collector.nested() add_breadcrumb(title="Delete", top_level=False, request=request) return render( request, 'dojo/delete_jira.html', { 'inst': jira_instance, 'form': form, 'rels': rels, 'deletable_objects': rels, })
def import_scan_results(request, eid=None, pid=None): engagement = None form = ImportScanForm() cred_form = CredMappingForm() finding_count = 0 jform = None user = request.user if eid: engagement = get_object_or_404(Engagement, id=eid) engagement_or_product = engagement cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(engagement=engagement).order_by('cred_id') elif pid: product = get_object_or_404(Product, id=pid) engagement_or_product = product elif not user.is_staff: raise PermissionDenied user_has_permission_or_403(user, engagement_or_product, Permissions.Import_Scan_Result) push_all_jira_issues = jira_helper.is_push_all_issues(engagement_or_product) if request.method == "POST": form = ImportScanForm(request.POST, request.FILES) cred_form = CredMappingForm(request.POST) cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter( engagement=engagement).order_by('cred_id') if jira_helper.get_jira_project(engagement_or_product): jform = JIRAImportScanForm(request.POST, push_all=push_all_jira_issues, prefix='jiraform') logger.debug('jform valid: %s', jform.is_valid()) logger.debug('jform errors: %s', jform.errors) if form.is_valid() and (jform is None or jform.is_valid()): scan = request.FILES.get('file', None) scan_date = form.cleaned_data['scan_date'] minimum_severity = form.cleaned_data['minimum_severity'] active = form.cleaned_data['active'] verified = form.cleaned_data['verified'] scan_type = request.POST['scan_type'] tags = form.cleaned_data['tags'] version = form.cleaned_data['version'] branch_tag = form.cleaned_data.get('branch_tag', None) build_id = form.cleaned_data.get('build_id', None) commit_hash = form.cleaned_data.get('commit_hash', None) api_scan_configuration = form.cleaned_data.get('api_scan_configuration', None) service = form.cleaned_data.get('service', None) close_old_findings = form.cleaned_data.get('close_old_findings', None) # Will save in the provided environment or in the `Development` one if absent environment_id = request.POST.get('environment', 'Development') environment = Development_Environment.objects.get(id=environment_id) group_by = form.cleaned_data.get('group_by', None) # TODO move to form validation? if scan and is_scan_file_too_large(scan): messages.add_message(request, messages.ERROR, "Report file is too large. Maximum supported size is {} MB".format(settings.SCAN_FILE_MAX_SIZE), extra_tags='alert-danger') return HttpResponseRedirect(reverse('import_scan_results', args=(engagement,))) # Allows for a test to be imported with an engagement created on the fly if engagement is None: engagement = Engagement() engagement.name = "AdHoc Import - " + strftime("%a, %d %b %Y %X", timezone.now().timetuple()) engagement.threat_model = False engagement.api_test = False engagement.pen_test = False engagement.check_list = False engagement.target_start = timezone.now().date() engagement.target_end = timezone.now().date() engagement.product = product engagement.active = True engagement.status = 'In Progress' engagement.version = version engagement.branch_tag = branch_tag engagement.build_id = build_id engagement.commit_hash = commit_hash engagement.save() # can't use helper as when push_all_jira_issues is True, the checkbox gets disabled and is always false # push_to_jira = jira_helper.is_push_to_jira(new_finding, jform.cleaned_data.get('push_to_jira')) push_to_jira = push_all_jira_issues or (jform and jform.cleaned_data.get('push_to_jira')) error = False # Save newly added endpoints added_endpoints = save_endpoints_to_add(form.endpoints_to_add_list, engagement.product) try: importer = Importer() test, finding_count, closed_finding_count = importer.import_scan(scan, scan_type, engagement, user, environment, active=active, verified=verified, tags=tags, minimum_severity=minimum_severity, endpoints_to_add=list(form.cleaned_data['endpoints']) + added_endpoints, scan_date=scan_date, version=version, branch_tag=branch_tag, build_id=build_id, commit_hash=commit_hash, push_to_jira=push_to_jira, close_old_findings=close_old_findings, group_by=group_by, api_scan_configuration=api_scan_configuration, service=service) message = f'{scan_type} processed a total of {finding_count} findings' if close_old_findings: message = message + ' and closed %d findings' % (closed_finding_count) message = message + "." add_success_message_to_response(message) except Exception as e: logger.exception(e) add_error_message_to_response('An exception error occurred during the report import:%s' % str(e)) error = True # Save the credential to the test if cred_form.is_valid(): if cred_form.cleaned_data['cred_user']: # Select the credential mapping object from the selected list and only allow if the credential is associated with the product cred_user = Cred_Mapping.objects.filter( pk=cred_form.cleaned_data['cred_user'].id, engagement=eid).first() new_f = cred_form.save(commit=False) new_f.test = test new_f.cred_id = cred_user.cred_id new_f.save() if not error: return HttpResponseRedirect( reverse('view_test', args=(test.id, ))) prod_id = None custom_breadcrumb = None title = "Import Scan Results" if engagement: prod_id = engagement.product.id product_tab = Product_Tab(prod_id, title=title, tab="engagements") product_tab.setEngagement(engagement) else: prod_id = pid custom_breadcrumb = {"", ""} product_tab = Product_Tab(prod_id, title=title, tab="findings") if jira_helper.get_jira_project(engagement_or_product): jform = JIRAImportScanForm(push_all=push_all_jira_issues, prefix='jiraform') form.fields['endpoints'].queryset = Endpoint.objects.filter(product__id=product_tab.product.id) form.fields['api_scan_configuration'].queryset = Product_API_Scan_Configuration.objects.filter(product__id=product_tab.product.id) return render(request, 'dojo/import_scan_results.html', {'form': form, 'product_tab': product_tab, 'engagement_or_product': engagement_or_product, 'custom_breadcrumb': custom_breadcrumb, 'title': title, 'cred_form': cred_form, 'jform': jform, 'scan_types': get_scan_types_sorted(), })
def re_import_scan_results(request, tid): additional_message = "When re-uploading a scan, any findings not found in original scan will be updated as " \ "mitigated. The process attempts to identify the differences, however manual verification " \ "is highly recommended." test = get_object_or_404(Test, id=tid) # by default we keep a trace of the scan_type used to create the test # if it's not here, we use the "name" of the test type # this feature exists to provide custom label for tests for some parsers if test.scan_type: scan_type = test.scan_type else: scan_type = test.test_type.name engagement = test.engagement form = ReImportScanForm(test=test) jform = None jira_project = jira_helper.get_jira_project(test) push_all_jira_issues = jira_helper.is_push_all_issues(test) # Decide if we need to present the Push to JIRA form if get_system_setting('enable_jira') and jira_project: jform = JIRAImportScanForm(push_all=push_all_jira_issues, prefix='jiraform') if request.method == "POST": form = ReImportScanForm(request.POST, request.FILES, test=test) if jira_project: jform = JIRAImportScanForm(request.POST, push_all=push_all_jira_issues, prefix='jiraform') if form.is_valid() and (jform is None or jform.is_valid()): scan_date = form.cleaned_data['scan_date'] minimum_severity = form.cleaned_data['minimum_severity'] scan = request.FILES.get('file', None) active = form.cleaned_data['active'] verified = form.cleaned_data['verified'] tags = form.cleaned_data['tags'] version = form.cleaned_data.get('version', None) branch_tag = form.cleaned_data.get('branch_tag', None) build_id = form.cleaned_data.get('build_id', None) commit_hash = form.cleaned_data.get('commit_hash', None) api_scan_configuration = form.cleaned_data.get( 'api_scan_configuration', None) service = form.cleaned_data.get('service', None) endpoints_to_add = None # not available on reimport UI close_old_findings = form.cleaned_data.get('close_old_findings', True) group_by = form.cleaned_data.get('group_by', None) # Tags are replaced, same behaviour as with django-tagging test.tags = tags test.version = version if scan and is_scan_file_too_large(scan): messages.add_message( request, messages.ERROR, "Report file is too large. Maximum supported size is {} MB" .format(settings.SCAN_FILE_MAX_SIZE), extra_tags='alert-danger') return HttpResponseRedirect( reverse('re_import_scan_results', args=(test.id, ))) push_to_jira = push_all_jira_issues or ( jform and jform.cleaned_data.get('push_to_jira')) error = False finding_count, new_finding_count, closed_finding_count, reactivated_finding_count, untouched_finding_count = 0, 0, 0, 0, 0 reimporter = ReImporter() try: test, finding_count, new_finding_count, closed_finding_count, reactivated_finding_count, untouched_finding_count, _ = \ reimporter.reimport_scan(scan, scan_type, test, active=active, verified=verified, tags=None, minimum_severity=minimum_severity, endpoints_to_add=endpoints_to_add, scan_date=scan_date, version=version, branch_tag=branch_tag, build_id=build_id, commit_hash=commit_hash, push_to_jira=push_to_jira, close_old_findings=close_old_findings, group_by=group_by, api_scan_configuration=api_scan_configuration, service=service) except Exception as e: logger.exception(e) add_error_message_to_response( 'An exception error occurred during the report import:%s' % str(e)) error = True if not error: message = construct_imported_message( scan_type, finding_count, new_finding_count=new_finding_count, closed_finding_count=closed_finding_count, reactivated_finding_count=reactivated_finding_count, untouched_finding_count=untouched_finding_count) add_success_message_to_response(message) return HttpResponseRedirect(reverse('view_test', args=(test.id, ))) product_tab = Product_Tab(engagement.product.id, title="Re-upload a %s" % scan_type, tab="engagements") product_tab.setEngagement(engagement) form.fields['endpoints'].queryset = Endpoint.objects.filter( product__id=product_tab.product.id) form.initial['api_scan_configuration'] = test.api_scan_configuration form.fields[ 'api_scan_configuration'].queryset = Product_API_Scan_Configuration.objects.filter( product__id=product_tab.product.id) return render( request, 'dojo/import_scan_results.html', { 'form': form, 'product_tab': product_tab, 'eid': engagement.id, 'additional_message': additional_message, 'jform': jform, 'scan_types': get_scan_types_sorted(), })
def add_temp_finding(request, tid, fid): jform = None test = get_object_or_404(Test, id=tid) finding = get_object_or_404(Finding_Template, id=fid) findings = Finding_Template.objects.all() push_all_jira_issues = jira_helper.is_push_all_issues(finding) if request.method == 'POST': form = AddFindingForm(request.POST, req_resp=None, product=test.engagement.product) if jira_helper.get_jira_project(test): jform = JIRAFindingForm( push_all=jira_helper.is_push_all_issues(test), prefix='jiraform', jira_project=jira_helper.get_jira_project(test), finding_form=form) logger.debug('jform valid: %s', jform.is_valid()) if (form['active'].value() is False or form['false_p'].value() ) and form['duplicate'].value() is False: closing_disabled = Note_Type.objects.filter( is_mandatory=True, is_active=True).count() if closing_disabled != 0: error_inactive = ValidationError( 'Can not set a finding as inactive without adding all mandatory notes', code='not_active_or_false_p_true') error_false_p = ValidationError( 'Can not set a finding as false positive without adding all mandatory notes', code='not_active_or_false_p_true') if form['active'].value() is False: form.add_error('active', error_inactive) if form['false_p'].value(): form.add_error('false_p', error_false_p) messages.add_message( request, messages.ERROR, 'Can not set a finding as inactive or false positive without adding all mandatory notes', extra_tags='alert-danger') if form.is_valid(): finding.last_used = timezone.now() finding.save() new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) new_finding.date = form.cleaned_data['date'] or datetime.today() finding_helper.update_finding_status(new_finding, request.user) new_finding.save(dedupe_option=False, false_history=False) # Save and add new endpoints finding_helper.add_endpoints(new_finding, form) new_finding.save(false_history=True) if 'jiraform-push_to_jira' in request.POST: jform = JIRAFindingForm( request.POST, prefix='jiraform', instance=new_finding, push_all=push_all_jira_issues, jira_project=jira_helper.get_jira_project(test), finding_form=form) if jform.is_valid(): if jform.cleaned_data.get('push_to_jira'): jira_helper.push_to_jira(new_finding) else: add_error_message_to_response( 'jira form validation failed: %s' % jform.errors) messages.add_message(request, messages.SUCCESS, 'Finding from template added successfully.', extra_tags='alert-success') return HttpResponseRedirect(reverse('view_test', args=(test.id, ))) else: messages.add_message( request, messages.ERROR, 'The form has errors, please correct them below.', extra_tags='alert-danger') else: form = AddFindingForm(req_resp=None, product=test.engagement.product, initial={ 'active': False, 'date': timezone.now().date(), 'verified': False, 'false_p': False, 'duplicate': False, 'out_of_scope': False, 'title': finding.title, 'description': finding.description, 'cwe': finding.cwe, 'severity': finding.severity, 'mitigation': finding.mitigation, 'impact': finding.impact, 'references': finding.references, 'numerical_severity': finding.numerical_severity }) if jira_helper.get_jira_project(test): jform = JIRAFindingForm( push_all=jira_helper.is_push_all_issues(test), prefix='jiraform', jira_project=jira_helper.get_jira_project(test), finding_form=form) # logger.debug('form valid: %s', form.is_valid()) # logger.debug('jform valid: %s', jform.is_valid()) # logger.debug('form errors: %s', form.errors) # logger.debug('jform errors: %s', jform.errors) # logger.debug('jform errors: %s', vars(jform)) product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render( request, 'dojo/add_findings.html', { 'form': form, 'product_tab': product_tab, 'jform': jform, 'findings': findings, 'temp': True, 'fid': finding.id, 'tid': test.id, 'test': test, })
def add_findings(request, tid): test = Test.objects.get(id=tid) form_error = False jform = None form = AddFindingForm(initial={'date': timezone.now().date()}, req_resp=None, product=test.engagement.product) push_all_jira_issues = jira_helper.is_push_all_issues(test) use_jira = jira_helper.get_jira_project(test) is not None if request.method == 'POST': form = AddFindingForm(request.POST, req_resp=None, product=test.engagement.product) if (form['active'].value() is False or form['false_p'].value() ) and form['duplicate'].value() is False: closing_disabled = Note_Type.objects.filter( is_mandatory=True, is_active=True).count() if closing_disabled != 0: error_inactive = ValidationError( 'Can not set a finding as inactive without adding all mandatory notes', code='inactive_without_mandatory_notes') error_false_p = ValidationError( 'Can not set a finding as false positive without adding all mandatory notes', code='false_p_without_mandatory_notes') if form['active'].value() is False: form.add_error('active', error_inactive) if form['false_p'].value(): form.add_error('false_p', error_false_p) messages.add_message( request, messages.ERROR, 'Can not set a finding as inactive or false positive without adding all mandatory notes', extra_tags='alert-danger') if use_jira: jform = JIRAFindingForm( request.POST, prefix='jiraform', push_all=push_all_jira_issues, jira_project=jira_helper.get_jira_project(test), finding_form=form) if form.is_valid() and (jform is None or jform.is_valid()): if jform: logger.debug('jform.jira_issue: %s', jform.cleaned_data.get('jira_issue')) logger.debug('jform.push_to_jira: %s', jform.cleaned_data.get('push_to_jira')) new_finding = form.save(commit=False) new_finding.test = test new_finding.reporter = request.user new_finding.numerical_severity = Finding.get_numerical_severity( new_finding.severity) new_finding.tags = form.cleaned_data['tags'] new_finding.save(dedupe_option=False, push_to_jira=False) # Save and add new endpoints finding_helper.add_endpoints(new_finding, form) # Push to jira? push_to_jira = False jira_message = None if jform and jform.is_valid(): # can't use helper as when push_all_jira_issues is True, the checkbox gets disabled and is always false # push_to_jira = jira_helper.is_push_to_jira(new_finding, jform.cleaned_data.get('push_to_jira')) push_to_jira = push_all_jira_issues or jform.cleaned_data.get( 'push_to_jira') # if the jira issue key was changed, update database new_jira_issue_key = jform.cleaned_data.get('jira_issue') if new_finding.has_jira_issue: jira_issue = new_finding.jira_issue # everything in DD around JIRA integration is based on the internal id of the issue in JIRA # instead of on the public jira issue key. # I have no idea why, but it means we have to retrieve the issue from JIRA to get the internal JIRA id. # we can assume the issue exist, which is already checked in the validation of the jform if not new_jira_issue_key: jira_helper.finding_unlink_jira(request, new_finding) jira_message = 'Link to JIRA issue removed successfully.' elif new_jira_issue_key != new_finding.jira_issue.jira_key: jira_helper.finding_unlink_jira(request, new_finding) jira_helper.finding_link_jira(request, new_finding, new_jira_issue_key) jira_message = 'Changed JIRA link successfully.' else: logger.debug('finding has no jira issue yet') if new_jira_issue_key: logger.debug( 'finding has no jira issue yet, but jira issue specified in request. trying to link.' ) jira_helper.finding_link_jira(request, new_finding, new_jira_issue_key) jira_message = 'Linked a JIRA issue successfully.' new_finding.save(false_history=True, push_to_jira=push_to_jira) create_notification(event='other', title='Addition of %s' % new_finding.title, finding=new_finding, description='Finding "%s" was added by %s' % (new_finding.title, request.user), url=request.build_absolute_uri( reverse('view_finding', args=(new_finding.id, ))), icon="exclamation-triangle") if 'request' in form.cleaned_data or 'response' in form.cleaned_data: burp_rr = BurpRawRequestResponse( finding=new_finding, burpRequestBase64=base64.b64encode( form.cleaned_data['request'].encode()), burpResponseBase64=base64.b64encode( form.cleaned_data['response'].encode()), ) burp_rr.clean() burp_rr.save() if '_Finished' in request.POST: return HttpResponseRedirect( reverse('view_test', args=(test.id, ))) else: return HttpResponseRedirect( reverse('add_findings', args=(test.id, ))) else: form_error = True add_error_message_to_response( 'The form has errors, please correct them below.') add_field_errors_to_response(jform) add_field_errors_to_response(form) else: if use_jira: jform = JIRAFindingForm( push_all=jira_helper.is_push_all_issues(test), prefix='jiraform', jira_project=jira_helper.get_jira_project(test), finding_form=form) product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements") product_tab.setEngagement(test.engagement) return render( request, 'dojo/add_findings.html', { 'form': form, 'product_tab': product_tab, 'test': test, 'temp': False, 'tid': tid, 'form_error': form_error, 'jform': jform, })
def endpoint_bulk_update_all(request, pid=None): if request.method == "POST": endpoints_to_update = request.POST.getlist('endpoints_to_update') finds = Endpoint.objects.filter( id__in=endpoints_to_update).order_by("endpoint_meta__product__id") total_endpoint_count = finds.count() if request.POST.get('delete_bulk_endpoints') and endpoints_to_update: if pid is None: if not request.user.is_staff: raise PermissionDenied else: product = get_object_or_404(Product, id=pid) user_has_permission_or_403(request.user, product, Permissions.Endpoint_Delete) finds = get_authorized_endpoints(Permissions.Endpoint_Delete, finds, request.user) skipped_endpoint_count = total_endpoint_count - finds.count() deleted_endpoint_count = finds.count() product_calc = list( Product.objects.filter( endpoint__id__in=endpoints_to_update).distinct()) finds.delete() for prod in product_calc: calculate_grade(prod) if skipped_endpoint_count > 0: add_error_message_to_response( 'Skipped deletion of {} endpoints because you are not authorized.' .format(skipped_endpoint_count)) if deleted_endpoint_count > 0: messages.add_message( request, messages.SUCCESS, 'Bulk delete of {} endpoints was successful.'.format( deleted_endpoint_count), extra_tags='alert-success') else: if endpoints_to_update: if pid is None: if not request.user.is_staff: raise PermissionDenied else: product = get_object_or_404(Product, id=pid) user_has_permission_or_403(request.user, product, Permissions.Finding_Edit) finds = get_authorized_endpoints(Permissions.Endpoint_Edit, finds, request.user) skipped_endpoint_count = total_endpoint_count - finds.count() updated_endpoint_count = finds.count() if skipped_endpoint_count > 0: add_error_message_to_response( 'Skipped mitigation of {} endpoints because you are not authorized.' .format(skipped_endpoint_count)) for endpoint in finds: endpoint.mitigated = not endpoint.mitigated endpoint.save() if updated_endpoint_count > 0: messages.add_message( request, messages.SUCCESS, 'Bulk mitigation of {} endpoints was successful.'. format(updated_endpoint_count), extra_tags='alert-success') else: messages.add_message( request, messages.ERROR, 'Unable to process bulk update. Required fields were not selected.', extra_tags='alert-danger') return HttpResponseRedirect(reverse('endpoint', args=()))