Пример #1
0
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=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
                   })
Пример #2
0
def async_pdf_report(self,
                     report=None,
                     template="None",
                     filename='report.pdf',
                     report_title=None,
                     report_subtitle=None,
                     report_info=None,
                     context={},
                     uri=None):
    xsl_style_sheet = settings.DOJO_ROOT + "/static/dojo/xsl/pdf_toc.xsl"
    x = urlencode({
        'title': report_title,
        'subtitle': report_subtitle,
        'info': report_info
    })

    cover = context['host'] + reverse('report_cover_page') + "?" + x

    config = pdfkit.configuration(wkhtmltopdf=settings.WKHTMLTOPDF_PATH)
    try:
        report.task_id = async_pdf_report.request.id
        report.status = 'running'
        report.save()
        bytes = render_to_string(template, context)
        itoc = context['include_table_of_contents']
        if itoc:
            toc = {'xsl-style-sheet': xsl_style_sheet}
        else:
            toc = None
        pdf = pdfkit.from_string(bytes,
                                 False,
                                 configuration=config,
                                 cover=cover,
                                 toc=toc,
                                 cover_first=True)
        if report.file.name:
            with open(report.file.path, 'w') as f:
                f.write(pdf)
            f.close()
        else:
            f = ContentFile(pdf)
            report.file.save(filename, f)
        report.status = 'success'
        report.done_datetime = timezone.now()
        report.save()

        create_notification(event='report_created',
                            title='Report created',
                            description='The report "%s" is ready.' %
                            report.name,
                            icon='file-text',
                            url=uri,
                            report=report,
                            objowner=report.requester)
    except Exception as e:
        report.status = 'error'
        report.save()
        # email_requester(report, uri, error=e)
        raise e
    return True
Пример #3
0
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
                   })
Пример #4
0
def add_alerts(self, runinterval):
    now = timezone.now()

    upcoming_engagements = Engagement.objects.filter(
        target_start__gt=now + timedelta(days=3),
        target_start__lt=now + timedelta(days=3) +
        runinterval).order_by('target_start')
    for engagement in upcoming_engagements:
        create_notification(event='upcoming_engagement',
                            title='Upcoming engagement: %s' % engagement.name,
                            engagement=engagement,
                            recipients=[engagement.lead],
                            url=request.build_absolute_uri(
                                reverse('view_engagement',
                                        args=(engagement.id, ))))

    stale_engagements = Engagement.objects.filter(
        target_start__gt=now - runinterval,
        target_end__lt=now,
        status='In Progress').order_by('-target_end')
    for eng in stale_engagements:
        create_notification(
            event='stale_engagement',
            title='Stale Engagement: %s' % eng.name,
            description='The engagement "%s" is stale. Target end was %s.' %
            (eng.name, eng.target_end.strftime("%b. %d, %Y")),
            url=reverse('view_engagement', args=(eng.id, )),
            recipients=[eng.lead])
Пример #5
0
def delete_jira(request, tid):
    jira_instance = get_object_or_404(JIRA_Conf, pk=tid)
    # eng = test.engagement
    # TODO Make Form
    form = DeleteJIRAConfForm(instance=jira_instance)

    if request.method == 'POST':
        if 'id' in request.POST and str(jira_instance.id) == request.POST['id']:
            form = DeleteJIRAConfForm(request.POST, instance=jira_instance)
            if form.is_valid():
                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 URL %s' % jira_instance.url,
                                    description='JIRA url "%s" was deleted by %s' % (jira_instance.url, request.user),
                                    url=request.build_absolute_uri(reverse('jira')),
                                    )
                return HttpResponseRedirect(reverse('jira'))

    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,
                   })
Пример #6
0
def delete_product(request, pid):
    product = get_object_or_404(Product, pk=pid)
    form = DeleteProductForm(instance=product)

    if request.method == 'POST':
        if 'id' in request.POST and str(product.id) == request.POST['id']:
            form = DeleteProductForm(request.POST, instance=product)
            if form.is_valid():
                if product.tags:
                    del product.tags
                product.delete()
                messages.add_message(request,
                                     messages.SUCCESS,
                                     'Product and relationships removed.',
                                     extra_tags='alert-success')
                create_notification(event='other',
                                    title='Deletion of %s' % product.name,
                                    description='The product "%s" was deleted by %s' % (product.name, request.user),
                                    url=request.build_absolute_uri(reverse('product')),
                                    icon="exclamation-triangle")
                return HttpResponseRedirect(reverse('product'))

    collector = NestedObjects(using=DEFAULT_DB_ALIAS)
    collector.collect([product])
    rels = collector.nested()

    product_tab = Product_Tab(pid, title="Product", tab="settings")
    return render(request, 'dojo/delete_product.html',
                  {'product': product,
                   'form': form,
                   'product_tab': product_tab,
                   'rels': rels,
                   })
Пример #7
0
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('"{0}"'.format(w) for w in 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')

            # SonarQube API Configuration
            sonarqube_form = Sonarqube_ProductForm(request.POST)
            if sonarqube_form.is_valid():
                sonarqube_product = sonarqube_form.save(commit=False)
                sonarqube_product.product = product
                sonarqube_product.save()

            create_notification(event='product_added',
                                title=product.name,
                                url=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,
        'sonarqube_form': Sonarqube_ProductForm()
    })
Пример #8
0
def add_tests(request, eid):
    eng = Engagement.objects.get(id=eid)
    cred_form = CredMappingForm()
    cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(engagement=eng).order_by('cred_id')

    if request.method == 'POST':
        form = TestForm(request.POST)
        cred_form = CredMappingForm(request.POST)
        cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(engagement=eng).order_by('cred_id')
        if form.is_valid():
            new_test = form.save(commit=False)
            new_test.engagement = eng
	    try:
            	new_test.lead = User.objects.get(id=form['lead'].value())
	    except:
		new_test.lead = None
		pass
            new_test.save()
            tags = request.POST.getlist('tags')
            t = ", ".join(tags)
            new_test.tags = t

            #Save the credential to the test
            if cred_form.is_valid():
                if cred_form.cleaned_data['cred_user']:
                    #Select the credential mapping object from the selected list and only allow if the credential is associated with the product
                    cred_user = Cred_Mapping.objects.filter(pk=cred_form.cleaned_data['cred_user'].id, engagement=eid).first()

                    new_f = cred_form.save(commit=False)
                    new_f.test = new_test
                    new_f.cred_id = cred_user.cred_id
                    new_f.save()

            messages.add_message(request,
                                 messages.SUCCESS,
                                 'Test added successfully.',
                                 extra_tags='alert-success')

            create_notification(event='test_added', title='Test added', test=new_test, engagement=eng, url=request.build_absolute_uri(reverse('view_engagement', args=(eng.id,))))

            if '_Add Another Test' in request.POST:
                return HttpResponseRedirect(reverse('add_tests', args=(eng.id,)))
            elif '_Add Findings' in request.POST:
                return HttpResponseRedirect(reverse('add_findings', args=(new_test.id,)))
            elif '_Finished' in request.POST:
                return HttpResponseRedirect(reverse('view_engagement', args=(eng.id,)))
    else:
        form = TestForm()
	form.initial['target_start'] = eng.target_start
	form.initial['target_end'] = eng.target_end
    add_breadcrumb(parent=eng, title="Add Tests", top_level=False, request=request)
    return render(request, 'dojo/add_tests.html',
                  {'form': form,
                  'cred_form': cred_form,
                  'eid': eid
                  })
Пример #9
0
def add_tests(request, eid):
    eng = Engagement.objects.get(id=eid)
    cred_form = CredMappingForm()
    cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(engagement=eng).order_by('cred_id')

    if request.method == 'POST':
        form = TestForm(request.POST)
        cred_form = CredMappingForm(request.POST)
        cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(engagement=eng).order_by('cred_id')
        if form.is_valid():
            new_test = form.save(commit=False)
            new_test.engagement = eng
	    try:
            	new_test.lead = User.objects.get(id=form['lead'].value())
	    except:
		new_test.lead = None
		pass
            new_test.save()
            tags = request.POST.getlist('tags')
            t = ", ".join(tags)
            new_test.tags = t

            #Save the credential to the test
            if cred_form.is_valid():
                if cred_form.cleaned_data['cred_user']:
                    #Select the credential mapping object from the selected list and only allow if the credential is associated with the product
                    cred_user = Cred_Mapping.objects.filter(pk=cred_form.cleaned_data['cred_user'].id, engagement=eid).first()

                    new_f = cred_form.save(commit=False)
                    new_f.test = new_test
                    new_f.cred_id = cred_user.cred_id
                    new_f.save()

            messages.add_message(request,
                                 messages.SUCCESS,
                                 'Test added successfully.',
                                 extra_tags='alert-success')

            create_notification(event='test_added', title='Test added', test=new_test, engagement=eng, url=request.build_absolute_uri(reverse('view_engagement', args=(eng.id,))))

            if '_Add Another Test' in request.POST:
                return HttpResponseRedirect(reverse('add_tests', args=(eng.id,)))
            elif '_Add Findings' in request.POST:
                return HttpResponseRedirect(reverse('add_findings', args=(new_test.id,)))
            elif '_Finished' in request.POST:
                return HttpResponseRedirect(reverse('view_engagement', args=(eng.id,)))
    else:
        form = TestForm()
	form.initial['target_start'] = eng.target_start
	form.initial['target_end'] = eng.target_end
    add_breadcrumb(parent=eng, title="Add Tests", top_level=False, request=request)
    return render(request, 'dojo/add_tests.html',
                  {'form': form,
                  'cred_form': cred_form,
                  'eid': eid
                  })
Пример #10
0
def request_finding_review(request, fid):
    finding = get_object_or_404(Finding, id=fid)
    user = get_object_or_404(Dojo_User, id=request.user.id)
    # in order to review a finding, we need to capture why a review is needed
    # we can do this with a Note
    if request.method == 'POST':
        form = ReviewFindingForm(request.POST)

        if form.is_valid():
            now = timezone.now()
            new_note = Notes()

            new_note.entry = "Review Request: " + form.cleaned_data['entry']
            new_note.author = request.user
            new_note.date = now
            new_note.save()
            finding.notes.add(new_note)
            finding.active = False
            finding.verified = False
            finding.under_review = True
            finding.review_requested_by = user
            finding.last_reviewed = now
            finding.last_reviewed_by = request.user

            users = form.cleaned_data['reviewers']
            finding.reviewers = users
            finding.save()

            create_notification(event='review_requested',
                               title='Finding review requested',
                               description='User %s has requested that you please review the finding "%s" for accuracy:\n\n%s' \
                                           % (user, finding.title, new_note),
                               icon='check',
                               url=request.build_absolute_uri(reverse("view_finding", args=(finding.id,))))

            messages.add_message(
                request,
                messages.SUCCESS,
                'Finding marked for review and reviewers notified.',
                extra_tags='alert-success')
            return HttpResponseRedirect(
                reverse('view_finding', args=(finding.id, )))

    else:
        form = ReviewFindingForm()

    add_breadcrumb(parent=finding,
                   title="Review Finding",
                   top_level=False,
                   request=request)
    return render(request, 'dojo/review_finding.html', {
        'finding': finding,
        'user': user,
        'form': form
    })
Пример #11
0
def async_pdf_report(self,
                     report=None,
                     template="None",
                     filename='report.pdf',
                     report_title=None,
                     report_subtitle=None,
                     report_info=None,
                     context={},
                     uri=None):
    xsl_style_sheet = settings.DOJO_ROOT + "/static/dojo/xsl/pdf_toc.xsl"
    x = urlencode({'title': report_title,
                   'subtitle': report_subtitle,
                   'info': report_info})

    cover = context['host'] + reverse(
        'report_cover_page') + "?" + x

    config = pdfkit.configuration(wkhtmltopdf=settings.WKHTMLTOPDF_PATH)
    try:
        report.task_id = async_pdf_report.request.id
        report.save()
        bytes = render_to_string(template, context)
        itoc = context['include_table_of_contents']
        if itoc:
            toc = {'xsl-style-sheet': xsl_style_sheet}
        else:
            toc = None
        pdf = pdfkit.from_string(bytes,
                                 False,
                                 configuration=config,
                                 cover=cover,
                                 toc=toc)
        if report.file.name:
            with open(report.file.path, 'w') as f:
                f.write(pdf)
            f.close()
        else:
            f = ContentFile(pdf)
            report.file.save(filename, f)
        report.status = 'success'
        report.done_datetime = timezone.now()
        report.save()

        create_notification(event='report_created', title='Report created', description='The report "%s" is ready.' % report.name, url=uri, report=report, objowner=report.requester)
    except Exception as e:
        report.status = 'error'
        report.save()
        # email_requester(report, uri, error=e)
        raise e
    return True
Пример #12
0
def add_alerts(self, runinterval):
    now = timezone.now()
    """
    upcoming_engagements = Engagement.objects.filter(target_start__gt=now + timedelta(days=3), target_start__lt=now + timedelta(days=3) + runinterval).order_by('target_start')
    for engagement in upcoming_engagements:
        create_notification(event='upcoming_engagement',
                            title='Upcoming engagement: %s' % engagement.name,
                            engagement=engagement,
                            recipients=[engagement.lead],
                            url=reverse('view_engagement', args=(engagement.id,)))

    stale_engagements = Engagement.objects.filter(
        target_start__gt=now - runinterval,
        target_end__lt=now,
        status='In Progress').order_by('-target_end')
    for eng in stale_engagements:
        create_notification(event='stale_engagement',
                            title='Stale Engagement: %s' % eng.name,
                            description='The engagement "%s" is stale. Target end was %s.' % (eng.name, eng.target_end.strftime("%b. %d, %Y")),
                            url=reverse('view_engagement', args=(eng.id,)),
                            recipients=[eng.lead])
    """
    system_settings = System_Settings.objects.get()
    if system_settings.engagement_auto_close:
        # Close Engagements older than user defined days
        close_days = system_settings.engagement_auto_close_days
        unclosed_engagements = Engagement.objects.filter(
            target_end__lte=now - timedelta(days=close_days),
            status='In Progress').order_by('target_end')

        for eng in unclosed_engagements:
            create_notification(
                event='auto_close_engagement',
                title=eng.name,
                description=
                'The engagement "%s" has auto-closed. Target end was %s.' %
                (eng.name, eng.target_end.strftime("%b. %d, %Y")),
                url=reverse('view_engagement', args=(eng.id, )),
                recipients=[eng.lead])

        unclosed_engagements.update(status="Completed",
                                    active=False,
                                    updated=timezone.now())

    # Calculate grade
    if system_settings.enable_product_grade:
        products = Product.objects.all()
        for product in products:
            calculate_grade(product)
Пример #13
0
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
                   })
Пример #14
0
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
                   })
Пример #15
0
def request_finding_review(request, fid):
    finding = get_object_or_404(Finding, id=fid)
    user = get_object_or_404(Dojo_User, id=request.user.id)
    # in order to review a finding, we need to capture why a review is needed
    # we can do this with a Note
    if request.method == 'POST':
        form = ReviewFindingForm(request.POST)

        if form.is_valid():
            now = timezone.now()
            new_note = Notes()

            new_note.entry = "Review Request: " + form.cleaned_data['entry']
            new_note.author = request.user
            new_note.date = now
            new_note.save()
            finding.notes.add(new_note)
            finding.active = False
            finding.verified = False
            finding.under_review = True
            finding.review_requested_by = user
            finding.last_reviewed = now
            finding.last_reviewed_by = request.user

            users = form.cleaned_data['reviewers']
            finding.reviewers = users
            finding.save()

            create_notification(event='review_requested',
                               title='Finding review requested',
                               description='User %s has requested that you please review the finding "%s" for accuracy:\n\n%s' \
                                           % (user, finding.title, new_note),
                               icon='check',
                               url=request.build_absolute_uri(reverse("view_finding", args=(finding.id,))))

            messages.add_message(request,
                                 messages.SUCCESS,
                                 'Finding marked for review and reviewers notified.',
                                 extra_tags='alert-success')
            return HttpResponseRedirect(reverse('view_finding', args=(finding.id,)))

    else:
        form = ReviewFindingForm()

    add_breadcrumb(parent=finding, title="Review Finding", top_level=False, request=request)
    return render(request, 'dojo/review_finding.html',
                  {'finding': finding,
                   'user': user, 'form': form})
Пример #16
0
def delete_engagement(request, eid):
    engagement = get_object_or_404(Engagement, pk=eid)
    product = engagement.product
    form = DeleteEngagementForm(instance=engagement)

    if request.method == 'POST':
        if 'id' in request.POST and str(engagement.id) == request.POST['id']:
            form = DeleteEngagementForm(request.POST, instance=engagement)
            if form.is_valid():
                del engagement.tags
                engagement.delete()
                messages.add_message(request,
                                     messages.SUCCESS,
                                     'Engagement and relationships removed.',
                                     extra_tags='alert-success')
                create_notification(
                    event='other',
                    title='Deletion of %s' % engagement.name,
                    description='The engagement "%s" was deleted by %s' %
                    (engagement.name, request.user),
                    url=request.build_absolute_uri(
                        reverse('view_engagements', args=(product.id, ))),
                    recipients=[engagement.lead],
                    icon="exclamation-triangle")

                if engagement.engagement_type == 'CI/CD':
                    return HttpResponseRedirect(
                        reverse("view_engagements_cicd", args=(product.id, )))
                else:
                    return HttpResponseRedirect(
                        reverse("view_engagements", args=(product.id, )))

    collector = NestedObjects(using=DEFAULT_DB_ALIAS)
    collector.collect([engagement])
    rels = collector.nested()

    product_tab = Product_Tab(product.id,
                              title="Delete Engagement",
                              tab="engagements")
    product_tab.setEngagement(engagement)
    return render(
        request, 'dojo/delete_engagement.html', {
            'product_tab': product_tab,
            'engagement': engagement,
            'form': form,
            'rels': rels,
        })
Пример #17
0
def edit_jira(request, jid):
    jira = JIRA_Conf.objects.get(pk=jid)
    if request.method == 'POST':
        jform = JIRAForm(request.POST, instance=jira)
        if jform.is_valid():
            try:
                jira_server = jform.cleaned_data.get('url').rstrip('/')
                jira_username = jform.cleaned_data.get('username')
                jira_password = jform.cleaned_data.get('password')

                # Instantiate JIRA instance for validating url, username and password
                JIRA(server=jira_server,
                     basic_auth=(jira_username, jira_password))

                new_j = jform.save(commit=False)
                new_j.url = jira_server
                new_j.save()
                messages.add_message(
                    request,
                    messages.SUCCESS,
                    'JIRA Configuration Successfully Created.',
                    extra_tags='alert-success')
                create_notification(
                    event='other',
                    title='Edit of JIRA URL %s' %
                    jform.cleaned_data.get('url').rstrip('/'),
                    description='JIRA url "%s" was edited by %s' %
                    (jform.cleaned_data.get('url').rstrip('/'), request.user),
                    url=request.build_absolute_uri(reverse('jira')),
                )
                return HttpResponseRedirect(reverse('jira', ))
            except Exception:
                messages.add_message(
                    request,
                    messages.ERROR,
                    'Unable to authenticate. Please check the URL, username, and password.',
                    extra_tags='alert-danger')
    else:
        jform = JIRAForm(instance=jira)
        add_breadcrumb(title="Edit JIRA Configuration",
                       top_level=False,
                       request=request)

    return render(request, 'dojo/edit_jira.html', {
        'jform': jform,
    })
Пример #18
0
def delete_test(request, tid):
    test = get_object_or_404(Test, pk=tid)
    eng = test.engagement
    form = DeleteTestForm(instance=test)

    if request.method == 'POST':
        if 'id' in request.POST and str(test.id) == request.POST['id']:
            form = DeleteTestForm(request.POST, instance=test)
            if form.is_valid():
                del test.tags
                test.delete()
                messages.add_message(request,
                                     messages.SUCCESS,
                                     'Test and relationships removed.',
                                     extra_tags='alert-success')
                create_notification(
                    event='other',
                    title='Deletion of %s' % test.title,
                    description='The test "%s" was deleted by %s' %
                    (test.title, request.user),
                    url=request.build_absolute_uri(
                        reverse('view_engagement', args=(eng.id, ))),
                    recipients=[test.engagement.lead],
                    icon="exclamation-triangle")
                return HttpResponseRedirect(
                    reverse('view_engagement', args=(eng.id, )))

    collector = NestedObjects(using=DEFAULT_DB_ALIAS)
    collector.collect([test])
    rels = collector.nested()

    product_tab = Product_Tab(test.engagement.product.id,
                              title="Delete Test",
                              tab="engagements")
    product_tab.setEngagement(test.engagement)
    return render(
        request, 'dojo/delete_test.html', {
            'test': test,
            'product_tab': product_tab,
            'form': form,
            'rels': rels,
            'deletable_objects': rels,
        })
Пример #19
0
def edit_product_type(request, ptid):
    pt = get_object_or_404(Product_Type, pk=ptid)
    pt_form = Product_TypeForm(instance=pt)
    delete_pt_form = Delete_Product_TypeForm(instance=pt)
    if request.method == "POST" and request.POST.get('edit_product_type'):
        pt_form = Product_TypeForm(request.POST, instance=pt)
        if pt_form.is_valid():
            pt = pt_form.save()
            messages.add_message(
                request,
                messages.SUCCESS,
                'Product type updated successfully.',
                extra_tags="alert-success",
            )
            return HttpResponseRedirect(reverse("product_type"))
    if request.method == "POST" and request.POST.get("delete_product_type"):
        form2 = Delete_Product_TypeForm(request.POST, instance=pt)
        if form2.is_valid():
            pt.delete()
            messages.add_message(
                request,
                messages.SUCCESS,
                "Product type Deleted successfully.",
                extra_tags="alert-success",
            )
            create_notification(
                event='other',
                title='Deletion of %s' % pt.name,
                description='The product type "%s" was deleted by %s' %
                (pt.name, request.user),
                url=request.build_absolute_uri(reverse('product_type')),
                icon="exclamation-triangle")
            return HttpResponseRedirect(reverse("product_type"))
    add_breadcrumb(title="Edit Product Type", top_level=False, request=request)
    return render(
        request, 'dojo/edit_product_type.html', {
            'name': 'Edit Product Type',
            'metric': False,
            'user': request.user,
            'pt_form': pt_form,
            'pt': pt
        })
Пример #20
0
def reopen_eng(request, eid):
    eng = Engagement.objects.get(id=eid)
    reopen_engagement(eng)
    messages.add_message(request,
                         messages.SUCCESS,
                         'Engagement reopened successfully.',
                         extra_tags='alert-success')
    create_notification(
        event='other',
        title='Reopening of %s' % eng.name,
        description='The engagement "%s" was reopened' % (eng.name),
        url=request.build_absolute_uri(
            reverse('view_engagements', args=(eng.product.id, ))),
    )
    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, )))
Пример #21
0
def add_alerts(self, runinterval):
    now = timezone.now()

    upcoming_engagements = Engagement.objects.filter(target_start__gt=now+timedelta(days=3),target_start__lt=now+timedelta(days=3)+runinterval).order_by('target_start')
    for engagement in upcoming_engagements:
        create_notification(event='upcoming_engagement',
                           title='Upcoming engagement: %s' % engagement.name,
                           engagement=engagement,
                           recipients=[engagement.lead],
                           url=request.build_absolute_uri(reverse('view_engagement', args=(engagement.id,))))

    stale_engagements = Engagement.objects.filter(
        target_start__gt=now-runinterval,
        target_end__lt=now,
        status='In Progress').order_by('-target_end')
    for eng in stale_engagements:
        create_notification(event='stale_engagement',
                           title='Stale Engagement: %s' % eng.name,
                           description='The engagement "%s" is stale. Target end was %s.' % (eng.name, eng.target_end.strftime("%b. %d, %Y")),
                           url=reverse('view_engagement', args=(eng.id,)),
                           recipients=[eng.lead])
Пример #22
0
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})
Пример #23
0
def add_alerts(self, runinterval):
    now = timezone.now()

    upcoming_engagements = Engagement.objects.filter(target_start__gt=now + timedelta(days=3), target_start__lt=now + timedelta(days=3) + runinterval).order_by('target_start')
    for engagement in upcoming_engagements:
        create_notification(event='upcoming_engagement',
                            title='Upcoming engagement: %s' % engagement.name,
                            engagement=engagement,
                            recipients=[engagement.lead],
                            url=reverse('view_engagement', args=(engagement.id,)))

    stale_engagements = Engagement.objects.filter(
        target_start__gt=now - runinterval,
        target_end__lt=now,
        status='In Progress').order_by('-target_end')
    for eng in stale_engagements:
        create_notification(event='stale_engagement',
                            title='Stale Engagement: %s' % eng.name,
                            description='The engagement "%s" is stale. Target end was %s.' % (eng.name, eng.target_end.strftime("%b. %d, %Y")),
                            url=reverse('view_engagement', args=(eng.id,)),
                            recipients=[eng.lead])

    system_settings = System_Settings.objects.get()
    if system_settings.engagement_auto_close:
        # Close Engagements older than user defined days
        close_days = system_settings.engagement_auto_close_days
        unclosed_engagements = Engagement.objects.filter(target_end__lte=now - timedelta(days=close_days),
                                                        status='In Progress').order_by('target_end')

        for eng in unclosed_engagements:
            create_notification(event='auto_close_engagement',
                                title=eng.name,
                                description='The engagement "%s" has auto-closed. Target end was %s.' % (eng.name, eng.target_end.strftime("%b. %d, %Y")),
                                url=reverse('view_engagement', args=(eng.id,)),
                                recipients=[eng.lead])

        unclosed_engagements.update(status="Completed", active=False, updated=timezone.now())

    # Calculate grade
    if system_settings.enable_product_grade:
        products = Product.objects.all()
        for product in products:
            calculate_grade(product)
Пример #24
0
def express_new_jira(request):
    if request.method == 'POST':
        jform = ExpressJIRAForm(request.POST, instance=JIRA_Conf())
        if jform.is_valid():
            try:
                jira_server = jform.cleaned_data.get('url').rstrip('/')
                jira_username = jform.cleaned_data.get('username')
                jira_password = jform.cleaned_data.get('password')
                # Instantiate JIRA instance for validating url, username and password
                try:
                    jira = JIRA(server=jira_server,
                         basic_auth=(jira_username, jira_password))
                except Exception:
                    messages.add_message(request,
                                     messages.ERROR,
                                     'Unable to authenticate. Please check the URL, username, and password.',
                                     extra_tags='alert-danger')
                    return render(request, 'dojo/express_new_jira.html',
                                            {'jform': jform})
                # authentication successful
                # Get the open and close keys
                issue_id = jform.cleaned_data.get('issue_key')
                key_url = jira_server + '/rest/api/latest/issue/' + issue_id + '/transitions?expand=transitions.fields'
                data = json.loads(requests.get(key_url, auth=(jira_username, jira_password)).text)
                for node in data['transitions']:
                    if node['to']['name'] == 'To Do':
                        open_key = int(node['to']['id'])
                    if node['to']['name'] == 'Done':
                        close_key = int(node['to']['id'])
                # Get the epic id name
                key_url = jira_server + '/rest/api/2/field'
                data = json.loads(requests.get(key_url, auth=(jira_username, jira_password)).text)
                for node in data:
                    if 'Epic Name' in node['clauseNames']:
                        epic_name = int(node['clauseNames'][0][3:-1])
                        break

                jira_conf = JIRA_Conf(username=jira_username,
                                        password=jira_password,
                                        url=jira_server,
                                        configuration_name=jform.cleaned_data.get('configuration_name'),
                                        info_mapping_severity='Lowest',
                                        low_mapping_severity='Low',
                                        medium_mapping_severity='Medium',
                                        high_mapping_severity='High',
                                        critical_mapping_severity='Highest',
                                        epic_name_id=epic_name,
                                        open_status_key=open_key,
                                        close_status_key=close_key,
                                        finding_text='',
                                        default_issue_type=jform.cleaned_data.get('default_issue_type'))
                jira_conf.save()
                messages.add_message(request,
                                     messages.SUCCESS,
                                     'JIRA Configuration Successfully Created.',
                                     extra_tags='alert-success')
                create_notification(event='other',
                                    title='New addition of JIRA URL %s' % jform.cleaned_data.get('url').rstrip('/'),
                                    description='JIRA url "%s" was added by %s' %
                                                (jform.cleaned_data.get('url').rstrip('/'), request.user),
                                    url=request.build_absolute_uri(reverse('jira')),
                                    )
                return HttpResponseRedirect(reverse('jira', ))
            except:
                messages.add_message(request,
                                     messages.ERROR,
                                     'Unable to query other reuierd fields. They must be entered manually.',
                                     extra_tags='alert-danger')
                return HttpResponseRedirect(reverse('add_jira', ))
            return render(request, 'dojo/express_new_jira.html',
                {'jform': jform})
    else:
        jform = ExpressJIRAForm()
        add_breadcrumb(title="New Jira Configuration (Express)", top_level=False, request=request)
    return render(request, 'dojo/express_new_jira.html',
                  {'jform': jform})
Пример #25
0
def import_scan_results(request, eid=None, pid=None):
    engagement = None
    form = ImportScanForm()
    cred_form = CredMappingForm()
    finding_count = 0
    enabled = False
    jform = None

    if eid:
        engagement = get_object_or_404(Engagement, id=eid)
        cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(
            engagement=engagement).order_by('cred_id')
        if get_system_setting(
                'enable_jira') and engagement.product.jira_pkey_set.first(
                ) is not None:
            enabled = engagement.product.jira_pkey_set.first().push_all_issues
            jform = JIRAFindingForm(enabled=enabled, prefix='jiraform')
    elif pid:
        product = get_object_or_404(Product, id=pid)
        if get_system_setting(
                'enable_jira') and product.jira_pkey_set.first() is not None:
            enabled = product.jira_pkey_set.first().push_all_issues
            jform = JIRAFindingForm(enabled=enabled, prefix='jiraform')

    if request.method == "POST":
        form = ImportScanForm(request.POST, request.FILES)
        cred_form = CredMappingForm(request.POST)
        cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(
            engagement=engagement).order_by('cred_id')

        if form.is_valid():
            # Allows for a test to be imported with an engagement created on the fly
            if engagement is None:
                engagement = Engagement()
                # product = get_object_or_404(Product, id=pid)
                engagement.name = "AdHoc Import - " + strftime(
                    "%a, %d %b %Y %X",
                    timezone.now().timetuple())
                engagement.threat_model = False
                engagement.api_test = False
                engagement.pen_test = False
                engagement.check_list = False
                engagement.target_start = timezone.now().date()
                engagement.target_end = timezone.now().date()
                engagement.product = product
                engagement.active = True
                engagement.status = 'In Progress'
                engagement.save()
            file = request.FILES.get('file')
            scan_date = form.cleaned_data['scan_date']
            min_sev = form.cleaned_data['minimum_severity']
            active = form.cleaned_data['active']
            verified = form.cleaned_data['verified']
            scan_type = request.POST['scan_type']
            if not any(scan_type in code
                       for code in ImportScanForm.SCAN_TYPE_CHOICES):
                raise Http404()

            tt, t_created = Test_Type.objects.get_or_create(name=scan_type)
            # will save in development environment
            environment, env_created = Development_Environment.objects.get_or_create(
                name="Development")
            t = Test(engagement=engagement,
                     test_type=tt,
                     target_start=scan_date,
                     target_end=scan_date,
                     environment=environment,
                     percent_complete=100)
            t.lead = request.user
            t.full_clean()
            t.save()
            tags = request.POST.getlist('tags')
            ts = ", ".join(tags)
            t.tags = ts

            # Save the credential to the test
            if cred_form.is_valid():
                if cred_form.cleaned_data['cred_user']:
                    # Select the credential mapping object from the selected list and only allow if the credential is associated with the product
                    cred_user = Cred_Mapping.objects.filter(
                        pk=cred_form.cleaned_data['cred_user'].id,
                        engagement=eid).first()

                    new_f = cred_form.save(commit=False)
                    new_f.test = t
                    new_f.cred_id = cred_user.cred_id
                    new_f.save()

            try:
                parser = import_parser_factory(file, t, active, verified)
            except Exception as e:
                messages.add_message(
                    request,
                    messages.ERROR,
                    "An error has occurred in the parser, please see error "
                    "log for details.",
                    extra_tags='alert-danger')
                parse_logger.exception(e)
                parse_logger.error("Error in parser: {}".format(str(e)))
                return HttpResponseRedirect(
                    reverse('import_scan_results', args=(eid, )))

            try:
                # Push to Jira?
                push_to_jira = False
                if enabled:
                    push_to_jira = True
                elif 'jiraform-push_to_jira' in request.POST:
                    jform = JIRAFindingForm(request.POST,
                                            prefix='jiraform',
                                            enabled=enabled)
                    if jform.is_valid():
                        push_to_jira = jform.cleaned_data.get('push_to_jira')

                for item in parser.items:
                    print("item blowup")
                    print(item)
                    sev = item.severity
                    if sev == 'Information' or sev == 'Informational':
                        sev = 'Info'

                    item.severity = sev

                    if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]:
                        continue

                    item.test = t
                    if item.date == timezone.now().date():
                        item.date = t.target_start

                    item.reporter = request.user
                    item.last_reviewed = timezone.now()
                    item.last_reviewed_by = request.user
                    if not handles_active_verified_statuses(
                            form.get_scan_type()):
                        item.active = active
                        item.verified = verified

                    item.save(dedupe_option=False, false_history=True)

                    if hasattr(item, 'unsaved_req_resp') and len(
                            item.unsaved_req_resp) > 0:
                        for req_resp in item.unsaved_req_resp:
                            if form.get_scan_type() == "Arachni Scan":
                                burp_rr = BurpRawRequestResponse(
                                    finding=item,
                                    burpRequestBase64=req_resp["req"],
                                    burpResponseBase64=req_resp["resp"],
                                )
                            else:
                                burp_rr = BurpRawRequestResponse(
                                    finding=item,
                                    burpRequestBase64=base64.b64encode(
                                        req_resp["req"].encode("utf-8")),
                                    burpResponseBase64=base64.b64encode(
                                        req_resp["resp"].encode("utf-8")),
                                )
                            burp_rr.clean()
                            burp_rr.save()

                    if item.unsaved_request is not None and item.unsaved_response is not None:
                        burp_rr = BurpRawRequestResponse(
                            finding=item,
                            burpRequestBase64=base64.b64encode(
                                item.unsaved_request.encode()),
                            burpResponseBase64=base64.b64encode(
                                item.unsaved_response.encode()),
                        )
                        burp_rr.clean()
                        burp_rr.save()

                    for endpoint in item.unsaved_endpoints:
                        ep, created = Endpoint.objects.get_or_create(
                            protocol=endpoint.protocol,
                            host=endpoint.host,
                            path=endpoint.path,
                            query=endpoint.query,
                            fragment=endpoint.fragment,
                            product=t.engagement.product)

                        item.endpoints.add(ep)
                    for endpoint in form.cleaned_data['endpoints']:
                        ep, created = Endpoint.objects.get_or_create(
                            protocol=endpoint.protocol,
                            host=endpoint.host,
                            path=endpoint.path,
                            query=endpoint.query,
                            fragment=endpoint.fragment,
                            product=t.engagement.product)

                        item.endpoints.add(ep)

                    item.save(false_history=True, push_to_jira=push_to_jira)

                    if item.unsaved_tags is not None:
                        item.tags = item.unsaved_tags

                    finding_count += 1

                messages.add_message(
                    request,
                    messages.SUCCESS,
                    scan_type + ' processed, a total of ' +
                    message(finding_count, 'finding', 'processed'),
                    extra_tags='alert-success')

                create_notification(event='results_added',
                                    initiator=request.user,
                                    title=str(finding_count) +
                                    " findings for " + engagement.product.name,
                                    finding_count=finding_count,
                                    test=t,
                                    engagement=engagement,
                                    url=reverse('view_test', args=(t.id, )))

                return HttpResponseRedirect(reverse('view_test',
                                                    args=(t.id, )))
            except SyntaxError:
                messages.add_message(
                    request,
                    messages.ERROR,
                    'There appears to be an error in the XML report, please check and try again.',
                    extra_tags='alert-danger')
    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")
    form.fields['endpoints'].queryset = Endpoint.objects.filter(
        product__id=product_tab.product.id)
    return render(
        request, 'dojo/import_scan_results.html', {
            'form': form,
            'product_tab': product_tab,
            'custom_breadcrumb': custom_breadcrumb,
            'title': title,
            'cred_form': cred_form,
            'jform': jform
        })
Пример #26
0
def import_object_eng(request, engagement, json_data):
    create_test_code_review = False
    create_alert = False

    #Get the product from the engagement
    product = engagement.product

    #Retrieve the files currently set for this product
    object_queryset = Objects.objects.filter(product=engagement.product.id).order_by('-path')
    data = json.load(json_data)

    #Set default review status
    review_status_id = 1
    review_status = Objects_Review.objects.get(pk=review_status_id)

    for file in data:
        print file["path"]
        #Save the file if the object isn't in object table
        file_type, found_object = find_item(file["path"], object_queryset)

        if found_object is None or file_type == "path":
            review_status_id = 1

            if file_type == "path":
                #Copy the review status
                review_status_id = found_object.review_status.id

            #Set default review status
            review_status = Objects_Review.objects.get(pk=review_status_id)

            #if found_object is None:
            object = Objects(product=product, path=file["path"], review_status=review_status)
            object.save()
            found_object = object
            if file_type == "path":
                for tag in found_object.tags.all():
                    Tag.objects.update_tags(object, tag.name)

        full_url = None
        type = None
        percentUnchanged = None
        build_id = None
        if "full_url" in file:
            full_url = file["full_url"]
        if "type" in file:
            type = file["type"]
        if "percentUnchanged" in file:
            percentUnchanged = file["percentUnchanged"]
        if "build_id" in file:
            build_id = file["build_id"][:12]

        #Find the status so the appropriate action takes place
        if found_object.review_status.id == 2:
            create_alert = True
        elif found_object.review_status.id == 3:
            create_test_code_review = True
            create_alert = True

        #Save the changed files to the engagement view
        object_eng = Objects_Engagement(engagement=engagement, object_id=found_object, full_url=full_url, type=type, percentUnchanged=percentUnchanged, build_id=build_id)
        object_eng.save()

    #Create the notification
    if create_alert:
        create_notification(event='code_review', title='Manual Code Review Requested', description="Manual code review requested as tracked file changes were found in the latest build.", engagement=engagement, url=request.build_absolute_uri(reverse('view_object_eng', args=(engagement.id,))))

    #Create the test within the engagement
    if create_test_code_review:
        environment, env_created = Development_Environment.objects.get_or_create(name="Development")
        tt = Test_Type.objects.get(pk=27) #Manual code review
        if tt:
            test = Test(engagement=engagement, test_type=tt, target_start=timezone.now(),
                     target_end=timezone.now() + timezone.timedelta(days=1), environment=environment, percent_complete=0)
            test.save()
            create_notification(event='test_added', title='Test added for Manual Code Review', test=test, engagement=engagement, url=request.build_absolute_uri(reverse('view_engagement', args=(engagement.id,))))
Пример #27
0
    def save(self):
        data = self.validated_data
        close_old_findings = data['close_old_findings']
        active = data['active']
        verified = data['verified']
        test_type, created = Test_Type.objects.get_or_create(
            name=data.get('test_type', data['scan_type']))
        environment, created = Development_Environment.objects.get_or_create(
            name='Development')
        test = Test(
            engagement=data['engagement'],
            lead=data['lead'],
            test_type=test_type,
            target_start=data['scan_date'],
            target_end=data['scan_date'],
            environment=environment,
            percent_complete=100)
        try:
            test.full_clean()
        except ValidationError:
            pass

        test.save()
        if 'tags' in data:
            test.tags = ' '.join(data['tags'])
        try:
            parser = import_parser_factory(data['file'],
                                           test,
                                           active,
                                           verified,
                                           data['scan_type'],)
        except ValueError:
            raise Exception('FileParser ValueError')

        skipped_hashcodes = []
        try:
            for item in parser.items:
                sev = item.severity
                if sev == 'Information' or sev == 'Informational':
                    sev = 'Info'

                item.severity = sev

                if (Finding.SEVERITIES[sev] >
                        Finding.SEVERITIES[data['minimum_severity']]):
                    continue

                item.test = test
                item.date = test.target_start
                item.reporter = self.context['request'].user
                item.last_reviewed = timezone.now()
                item.last_reviewed_by = self.context['request'].user
                item.active = data['active']
                item.verified = data['verified']
                item.save(dedupe_option=False)

                if (hasattr(item, 'unsaved_req_resp') and
                        len(item.unsaved_req_resp) > 0):
                    for req_resp in item.unsaved_req_resp:
                        burp_rr = BurpRawRequestResponse(
                            finding=item,
                            burpRequestBase64=req_resp["req"],
                            burpResponseBase64=req_resp["resp"])
                        burp_rr.clean()
                        burp_rr.save()

                if (item.unsaved_request is not None and
                        item.unsaved_response is not None):
                    burp_rr = BurpRawRequestResponse(
                        finding=item,
                        burpRequestBase64=item.unsaved_request,
                        burpResponseBase64=item.unsaved_response)
                    burp_rr.clean()
                    burp_rr.save()

                for endpoint in item.unsaved_endpoints:
                    ep, created = Endpoint.objects.get_or_create(
                        protocol=endpoint.protocol,
                        host=endpoint.host,
                        path=endpoint.path,
                        query=endpoint.query,
                        fragment=endpoint.fragment,
                        product=test.engagement.product)

                    item.endpoints.add(ep)

                if item.unsaved_tags is not None:
                    item.tags = item.unsaved_tags

                item.save()

        except SyntaxError:
            raise Exception('Parser SyntaxError')

        if close_old_findings:
            # Close old active findings that are not reported by this scan.
            new_hash_codes = test.finding_set.values('hash_code')

            old_findings = None
            if test.engagement.deduplication_on_engagement:
                old_findings = Finding.objects.exclude(test=test) \
                                              .exclude(hash_code__in=new_hash_codes) \
                                              .exclude(hash_code__in=skipped_hashcodes) \
                                              .filter(test__engagement=test.engagement,
                                                  test__test_type=test_type,
                                                  active=True)
            else:
                old_findings = Finding.objects.exclude(test=test) \
                                              .exclude(hash_code__in=new_hash_codes) \
                                              .exclude(hash_code__in=skipped_hashcodes) \
                                              .filter(test__engagement__product=test.engagement.product,
                                                  test__test_type=test_type,
                                                  active=True)

            for old_finding in old_findings:
                old_finding.active = False
                old_finding.mitigated = datetime.datetime.combine(
                    test.target_start,
                    timezone.now().time())
                if settings.USE_TZ:
                    old_finding.mitigated = timezone.make_aware(
                        old_finding.mitigated,
                        timezone.get_default_timezone())
                old_finding.mitigated_by = self.context['request'].user
                old_finding.notes.create(author=self.context['request'].user,
                                         entry="This finding has been automatically closed"
                                         " as it is not present anymore in recent scans.")
                Tag.objects.add_tag(old_finding, 'stale')
                old_finding.save()
                title = 'An old finding has been closed for "{}".' \
                        .format(test.engagement.product.name)
                description = 'See <a href="{}">{}</a>' \
                        .format(reverse('view_finding', args=(old_finding.id, )),
                                old_finding.title)
                create_notification(event='other',
                                    title=title,
                                    description=description,
                                    icon='bullseye',
                                    objowner=self.context['request'].user)

        return test
Пример #28
0
def re_import_scan_results(request, tid):
    additional_message = "When re-uploading a scan, any findings not found in original scan will be updated as " \
                         "mitigated.  The process attempts to identify the differences, however manual verification " \
                         "is highly recommended."
    test = get_object_or_404(Test, id=tid)
    scan_type = test.test_type.name
    engagement = test.engagement
    form = ReImportScanForm()
    jform = None
    enabled = False

    # Decide if we need to present the Push to JIRA form
    if get_system_setting(
            'enable_jira') and engagement.product.jira_pkey_set.first(
            ) is not None:
        enabled = engagement.product.jira_pkey_set.first().push_all_issues
        jform = JIRAFindingForm(enabled=enabled, prefix='jiraform')

    form.initial['tags'] = [tag.name for tag in test.tags]
    if request.method == "POST":
        form = ReImportScanForm(request.POST, request.FILES)
        if form.is_valid():
            scan_date = form.cleaned_data['scan_date']

            scan_date_time = datetime.combine(scan_date, timezone.now().time())
            if settings.USE_TZ:
                scan_date_time = timezone.make_aware(
                    scan_date_time, timezone.get_default_timezone())

            min_sev = form.cleaned_data['minimum_severity']
            file = request.FILES['file']
            scan_type = test.test_type.name
            active = form.cleaned_data['active']
            verified = form.cleaned_data['verified']
            tags = request.POST.getlist('tags')
            ts = ", ".join(tags)
            test.tags = ts
            try:
                parser = import_parser_factory(file, test, active, verified)
            except ValueError:
                raise Http404()
            except Exception as e:
                messages.add_message(
                    request,
                    messages.ERROR,
                    "An error has occurred in the parser, please see error "
                    "log for details.",
                    extra_tags='alert-danger')
                parse_logger.exception(e)
                parse_logger.error("Error in parser: {}".format(str(e)))
                return HttpResponseRedirect(
                    reverse('re_import_scan_results', args=(test.id, )))

            try:
                items = parser.items
                original_items = test.finding_set.all().values_list("id",
                                                                    flat=True)
                new_items = []
                mitigated_count = 0
                finding_count = 0
                finding_added_count = 0
                reactivated_count = 0
                # Push to Jira?

                push_to_jira = False
                if enabled:
                    push_to_jira = True
                elif 'jiraform-push_to_jira' in request.POST:
                    jform = JIRAFindingForm(request.POST,
                                            prefix='jiraform',
                                            enabled=enabled)
                    if jform.is_valid():
                        push_to_jira = jform.cleaned_data.get('push_to_jira')
                for item in items:

                    sev = item.severity
                    if sev == 'Information' or sev == 'Informational':
                        sev = 'Info'
                        item.severity = sev

                    # If it doesn't clear minimum severity, move on
                    if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]:
                        continue

                    # Try to find the existing finding
                    # If it's Veracode or Arachni, then we consider the description for some
                    # reason...
                    if scan_type == 'Veracode Scan' or scan_type == 'Arachni Scan':
                        finding = Finding.objects.filter(
                            title=item.title,
                            test__id=test.id,
                            severity=sev,
                            numerical_severity=Finding.get_numerical_severity(
                                sev),
                            description=item.description)

                    else:
                        finding = Finding.objects.filter(
                            title=item.title,
                            test__id=test.id,
                            severity=sev,
                            numerical_severity=Finding.get_numerical_severity(
                                sev))

                    if len(finding) == 1:
                        finding = finding[0]
                        if finding.mitigated or finding.is_Mitigated:
                            # it was once fixed, but now back
                            finding.mitigated = None
                            finding.is_Mitigated = False
                            finding.mitigated_by = None
                            finding.active = True
                            finding.verified = verified
                            finding.save()
                            note = Notes(
                                entry="Re-activated by %s re-upload." %
                                scan_type,
                                author=request.user)
                            note.save()
                            finding.notes.add(note)
                            reactivated_count += 1
                        new_items.append(finding.id)
                    else:
                        item.test = test
                        if item.date == timezone.now().date():
                            item.date = test.target_start
                        item.reporter = request.user
                        item.last_reviewed = timezone.now()
                        item.last_reviewed_by = request.user
                        item.verified = verified
                        item.active = active
                        # Save it
                        item.save(dedupe_option=False)
                        finding_added_count += 1
                        # Add it to the new items
                        new_items.append(item.id)
                        finding = item

                        if hasattr(item, 'unsaved_req_resp') and len(
                                item.unsaved_req_resp) > 0:
                            for req_resp in item.unsaved_req_resp:
                                if scan_type == "Arachni Scan":
                                    burp_rr = BurpRawRequestResponse(
                                        finding=item,
                                        burpRequestBase64=req_resp["req"],
                                        burpResponseBase64=req_resp["resp"],
                                    )
                                else:
                                    burp_rr = BurpRawRequestResponse(
                                        finding=item,
                                        burpRequestBase64=base64.b64encode(
                                            req_resp["req"].encode("utf-8")),
                                        burpResponseBase64=base64.b64encode(
                                            req_resp["resp"].encode("utf-8")),
                                    )
                                burp_rr.clean()
                                burp_rr.save()

                        if item.unsaved_request is not None and item.unsaved_response is not None:
                            burp_rr = BurpRawRequestResponse(
                                finding=finding,
                                burpRequestBase64=base64.b64encode(
                                    item.unsaved_request.encode()),
                                burpResponseBase64=base64.b64encode(
                                    item.unsaved_response.encode()),
                            )
                            burp_rr.clean()
                            burp_rr.save()
                    if finding:
                        finding_count += 1
                        for endpoint in item.unsaved_endpoints:
                            ep, created = Endpoint.objects.get_or_create(
                                protocol=endpoint.protocol,
                                host=endpoint.host,
                                path=endpoint.path,
                                query=endpoint.query,
                                fragment=endpoint.fragment,
                                product=test.engagement.product)
                            finding.endpoints.add(ep)
                        for endpoint in form.cleaned_data['endpoints']:
                            ep, created = Endpoint.objects.get_or_create(
                                protocol=endpoint.protocol,
                                host=endpoint.host,
                                path=endpoint.path,
                                query=endpoint.query,
                                fragment=endpoint.fragment,
                                product=test.engagement.product)
                            finding.endpoints.add(ep)

                        if item.unsaved_tags is not None:
                            finding.tags = item.unsaved_tags

                    # Save it. This may be the second time we save it in this function.
                    finding.save(push_to_jira=push_to_jira)
                # calculate the difference
                to_mitigate = set(original_items) - set(new_items)
                for finding_id in to_mitigate:
                    finding = Finding.objects.get(id=finding_id)
                    if not finding.mitigated or not finding.is_Mitigated:
                        finding.mitigated = scan_date_time
                        finding.is_Mitigated = True
                        finding.mitigated_by = request.user
                        finding.active = False
                        finding.save()
                        note = Notes(entry="Mitigated by %s re-upload." %
                                     scan_type,
                                     author=request.user)
                        note.save()
                        finding.notes.add(note)
                        mitigated_count += 1

                test.updated = max_safe([scan_date_time, test.updated])
                test.engagement.updated = max_safe(
                    [scan_date_time, test.engagement.updated])

                test.save()
                test.engagement.save()

                messages.add_message(
                    request,
                    messages.SUCCESS,
                    '%s processed, a total of ' % scan_type +
                    message(finding_count, 'finding', 'processed'),
                    extra_tags='alert-success')
                if finding_added_count > 0:
                    messages.add_message(
                        request,
                        messages.SUCCESS,
                        'A total of ' +
                        message(finding_added_count, 'finding', 'added') +
                        ', that are new to scan.',
                        extra_tags='alert-success')
                if reactivated_count > 0:
                    messages.add_message(
                        request,
                        messages.SUCCESS,
                        'A total of ' +
                        message(reactivated_count, 'finding', 'reactivated') +
                        ', that are back in scan results.',
                        extra_tags='alert-success')
                if mitigated_count > 0:
                    messages.add_message(
                        request,
                        messages.SUCCESS,
                        'A total of ' +
                        message(mitigated_count, 'finding', 'mitigated') +
                        '. Please manually verify each one.',
                        extra_tags='alert-success')

                create_notification(event='results_added',
                                    title=str(finding_count) +
                                    " findings for " +
                                    test.engagement.product.name,
                                    finding_count=finding_count,
                                    test=test,
                                    engagement=test.engagement,
                                    url=reverse('view_test', args=(test.id, )))

                return HttpResponseRedirect(
                    reverse('view_test', args=(test.id, )))
            except SyntaxError:
                messages.add_message(
                    request,
                    messages.ERROR,
                    'There appears to be an error in the XML report, please check and try again.',
                    extra_tags='alert-danger')

    product_tab = Product_Tab(engagement.product.id,
                              title="Re-upload a %s" % scan_type,
                              tab="engagements")
    product_tab.setEngagement(engagement)
    form.fields['endpoints'].queryset = Endpoint.objects.filter(
        product__id=product_tab.product.id)
    return render(
        request, 'dojo/import_scan_results.html', {
            'form': form,
            'product_tab': product_tab,
            'eid': engagement.id,
            'additional_message': additional_message,
            'jform': jform,
        })
Пример #29
0
def add_findings(request, tid):
    test = Test.objects.get(id=tid)
    form_error = False
    enabled = False
    jform = None
    form = AddFindingForm(initial={'date': timezone.now().date()})

    if get_system_setting('enable_jira') and JIRA_PKey.objects.filter(product=test.engagement.product).count() != 0:
        enabled = JIRA_PKey.objects.get(product=test.engagement.product).push_all_issues
        jform = JIRAFindingForm(enabled=enabled, prefix='jiraform')
    else:
        jform = None

    if request.method == 'POST':
        form = AddFindingForm(request.POST)
        if form['active'].value() is False or form['verified'].value() is False and 'jiraform-push_to_jira' in request.POST:
            error = ValidationError('Findings must be active and verified to be pushed to JIRA',
                                    code='not_active_or_verified')
            if form['active'].value() is False:
                form.add_error('active', error)
            if form['verified'].value() is False:
                form.add_error('verified', error)
            messages.add_message(request,
                                 messages.ERROR,
                                 'Findings must be active and verified to be pushed to JIRA',
                                 extra_tags='alert-danger')
        if form['severity'].value() == 'Info' and 'jiraform-push_to_jira' in request.POST:
            error = ValidationError('Findings with Informational severity cannot be pushed to JIRA.',
                                    code='info-severity-to-jira')
        if form.is_valid():
            new_finding = form.save(commit=False)
            new_finding.test = test
            new_finding.reporter = request.user
            new_finding.numerical_severity = Finding.get_numerical_severity(
                new_finding.severity)
            if new_finding.false_p or new_finding.active is False:
                new_finding.mitigated = timezone.now()
                new_finding.mitigated_by = request.user
            create_template = new_finding.is_template
            # always false now since this will be deprecated soon in favor of new Finding_Template model
            new_finding.is_template = False
            new_finding.save(dedupe_option=False)
            new_finding.endpoints.set(form.cleaned_data['endpoints'])
            new_finding.save(false_history=True)
            create_notification(event='other',
                                title='Addition of %s' % new_finding.title,
                                description='Finding "%s" was added by %s' % (new_finding.title, request.user),
                                url=request.build_absolute_uri(reverse('view_finding', args=(new_finding.id,))),
                                icon="exclamation-triangle")
            if 'jiraform-push_to_jira' in request.POST:
                jform = JIRAFindingForm(request.POST, prefix='jiraform', enabled=enabled)
                if jform.is_valid():
                    add_issue_task.delay(new_finding, jform.cleaned_data.get('push_to_jira'))
                messages.add_message(request,
                                     messages.SUCCESS,
                                     'Finding added successfully.',
                                     extra_tags='alert-success')
            if create_template:
                templates = Finding_Template.objects.filter(title=new_finding.title)
                if len(templates) > 0:
                    messages.add_message(request,
                                         messages.ERROR,
                                         'A finding template was not created.  A template with this title already '
                                         'exists.',
                                         extra_tags='alert-danger')
                else:
                    template = Finding_Template(title=new_finding.title,
                                                cwe=new_finding.cwe,
                                                severity=new_finding.severity,
                                                description=new_finding.description,
                                                mitigation=new_finding.mitigation,
                                                impact=new_finding.impact,
                                                references=new_finding.references,
                                                numerical_severity=new_finding.numerical_severity)
                    template.save()
                    messages.add_message(request,
                                         messages.SUCCESS,
                                         'A finding template was also created.',
                                         extra_tags='alert-success')
            if '_Finished' in request.POST:
                return HttpResponseRedirect(reverse('view_test', args=(test.id,)))
            else:
                return HttpResponseRedirect(reverse('add_findings', args=(test.id,)))
        else:
            if 'endpoints' in form.cleaned_data:
                form.fields['endpoints'].queryset = form.cleaned_data['endpoints']
            else:
                form.fields['endpoints'].queryset = Endpoint.objects.none()
            form_error = True
            messages.add_message(request,
                                 messages.ERROR,
                                 'The form has errors, please correct them below.',
                                 extra_tags='alert-danger')
    product_tab = Product_Tab(test.engagement.product.id, title="Add Finding", tab="engagements")
    product_tab.setEngagement(test.engagement)
    return render(request, 'dojo/add_findings.html',
                  {'form': form,
                   'product_tab': product_tab,
                   'test': test,
                   'temp': False,
                   'tid': tid,
                   'form_error': form_error,
                   'jform': jform,
                   })
Пример #30
0
def import_scan_results(request, eid=None, pid=None):
    engagement = None
    form = ImportScanForm()
    cred_form = CredMappingForm()
    finding_count = 0

    if eid:
        engagement = get_object_or_404(Engagement, id=eid)
        cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(
            engagement=engagement).order_by('cred_id')

    if request.method == "POST":
        form = ImportScanForm(request.POST, request.FILES)
        cred_form = CredMappingForm(request.POST)
        cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(
            engagement=engagement).order_by('cred_id')
        if form.is_valid():
            # Allows for a test to be imported with an engagement created on the fly
            if engagement is None:
                engagement = Engagement()
                product = get_object_or_404(Product, id=pid)
                engagement.name = "AdHoc Import - " + strftime(
                    "%a, %d %b %Y %X",
                    timezone.now().timetuple())
                engagement.threat_model = False
                engagement.api_test = False
                engagement.pen_test = False
                engagement.check_list = False
                engagement.target_start = timezone.now().date()
                engagement.target_end = timezone.now().date()
                engagement.product = product
                engagement.active = True
                engagement.status = 'In Progress'
                engagement.save()
            file = request.FILES['file']
            scan_date = form.cleaned_data['scan_date']
            min_sev = form.cleaned_data['minimum_severity']
            active = form.cleaned_data['active']
            verified = form.cleaned_data['verified']

            scan_type = request.POST['scan_type']
            if not any(scan_type in code
                       for code in ImportScanForm.SCAN_TYPE_CHOICES):
                raise Http404()

            tt, t_created = Test_Type.objects.get_or_create(name=scan_type)
            # will save in development environment
            environment, env_created = Development_Environment.objects.get_or_create(
                name="Development")
            t = Test(engagement=engagement,
                     test_type=tt,
                     target_start=scan_date,
                     target_end=scan_date,
                     environment=environment,
                     percent_complete=100)
            t.lead = request.user
            t.full_clean()
            t.save()
            tags = request.POST.getlist('tags')
            ts = ", ".join(tags)
            t.tags = ts

            # Save the credential to the test
            if cred_form.is_valid():
                if cred_form.cleaned_data['cred_user']:
                    # Select the credential mapping object from the selected list and only allow if the credential is associated with the product
                    cred_user = Cred_Mapping.objects.filter(
                        pk=cred_form.cleaned_data['cred_user'].id,
                        engagement=eid).first()

                    new_f = cred_form.save(commit=False)
                    new_f.test = t
                    new_f.cred_id = cred_user.cred_id
                    new_f.save()

            try:
                parser = import_parser_factory(file, t)
            except ValueError:
                raise Http404()

            try:
                for item in parser.items:
                    sev = item.severity
                    if sev == 'Information' or sev == 'Informational':
                        sev = 'Info'

                    item.severity = sev

                    if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]:
                        continue

                    item.test = t
                    if item.date == timezone.now().date():
                        item.date = t.target_start

                    item.reporter = request.user
                    item.last_reviewed = timezone.now()
                    item.last_reviewed_by = request.user
                    item.active = active
                    item.verified = verified
                    item.save(dedupe_option=False)

                    if hasattr(item, 'unsaved_req_resp') and len(
                            item.unsaved_req_resp) > 0:
                        for req_resp in item.unsaved_req_resp:
                            burp_rr = BurpRawRequestResponse(
                                finding=item,
                                burpRequestBase64=req_resp["req"],
                                burpResponseBase64=req_resp["resp"],
                            )
                            burp_rr.clean()
                            burp_rr.save()

                    if item.unsaved_request is not None and item.unsaved_response is not None:
                        burp_rr = BurpRawRequestResponse(
                            finding=item,
                            burpRequestBase64=item.unsaved_request,
                            burpResponseBase64=item.unsaved_response,
                        )
                        burp_rr.clean()
                        burp_rr.save()

                    for endpoint in item.unsaved_endpoints:
                        ep, created = Endpoint.objects.get_or_create(
                            protocol=endpoint.protocol,
                            host=endpoint.host,
                            path=endpoint.path,
                            query=endpoint.query,
                            fragment=endpoint.fragment,
                            product=t.engagement.product)

                        item.endpoints.add(ep)
                    item.save()

                    if item.unsaved_tags is not None:
                        item.tags = item.unsaved_tags
                    # patched: I have to add the jira creation in line below
                    add_issue(item, True)
                    finding_count += 1

                messages.add_message(
                    request,
                    messages.SUCCESS,
                    scan_type + ' processed, a total of ' +
                    message(finding_count, 'finding', 'processed'),
                    extra_tags='alert-success')

                create_notification(event='results_added',
                                    title=str(finding_count) +
                                    " findings for " + engagement.product.name,
                                    finding_count=finding_count,
                                    test=t,
                                    engagement=engagement,
                                    url=request.build_absolute_uri(
                                        reverse('view_test', args=(t.id, ))))

                return HttpResponseRedirect(reverse('view_test',
                                                    args=(t.id, )))
            except SyntaxError:
                messages.add_message(
                    request,
                    messages.ERROR,
                    'There appears to be an error in the XML report, please check and try again.',
                    extra_tags='alert-danger')
    prod_id = None
    custom_breadcrumb = None
    title = "Import Scan Results"
    if engagement:
        prod_id = engagement.product.id
        product_tab = Product_Tab(prod_id, title=title, tab="engagements")
        product_tab.setEngagement(engagement)
    else:
        prod_id = pid
        custom_breadcrumb = {"", ""}
        product_tab = Product_Tab(prod_id, title=title, tab="findings")

    return render(
        request, 'dojo/import_scan_results.html', {
            'form': form,
            'product_tab': product_tab,
            'custom_breadcrumb': custom_breadcrumb,
            'title': title,
            'cred_form': cred_form,
        })
Пример #31
0
def import_scan_results(request, eid):
    engagement = get_object_or_404(Engagement, id=eid)
    finding_count = 0
    form = ImportScanForm()

    if request.method == "POST":
        form = ImportScanForm(request.POST, request.FILES)
        if form.is_valid():
            file = request.FILES['file']
            scan_date = form.cleaned_data['scan_date']
            min_sev = form.cleaned_data['minimum_severity']

            scan_type = request.POST['scan_type']
            if not any(scan_type in code for code in ImportScanForm.SCAN_TYPE_CHOICES):
                raise Http404()

            tt, t_created = Test_Type.objects.get_or_create(name=scan_type)
            # will save in development environment
            environment, env_created = Development_Environment.objects.get_or_create(name="Development")
            t = Test(engagement=engagement, test_type=tt)
            t.full_clean()
            t.save()
            tags = request.POST.getlist('tags')
            ts = ", ".join(tags)
            t.tags = ts


            try:
                parser = import_parser_factory(file, t)
            except ValueError:
                raise Http404()

            try:
                for item in parser.items:
                    sev = item.severity
                    if sev == 'Information' or sev == 'Informational':
                        sev = 'Info'

                    item.severity = sev

                    if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]:
                        continue

                    item.test = t
                    item.date = timezone.now()
                    item.reporter = request.user
                    item.last_reviewed = timezone.now()
                    item.last_reviewed_by = request.user
                    item.save()

                    if hasattr(item, 'unsaved_req_resp') and len(item.unsaved_req_resp) > 0:
                        for req_resp in item.unsaved_req_resp:
                            burp_rr = BurpRawRequestResponse(finding=item,
                                                             burpRequestBase64=req_resp["req"],
                                                             burpResponseBase64=req_resp["resp"],
                                                             )
                            burp_rr.clean()
                            burp_rr.save()

                    if item.unsaved_request is not None and item.unsaved_response is not None:
                        burp_rr = BurpRawRequestResponse(finding=item,
                                                         burpRequestBase64=item.unsaved_request,
                                                         burpResponseBase64=item.unsaved_response,
                                                         )
                        burp_rr.clean()
                        burp_rr.save()

                    for endpoint in item.unsaved_endpoints:
                        ep, created = Endpoint.objects.get_or_create(protocol=endpoint.protocol,
                                                                     host=endpoint.host,
                                                                     fqdn=endpoint.fqdn,
                                                                     port=endpoint.port,
                                                                     path=endpoint.path,
                                                                     query=endpoint.query,
                                                                     fragment=endpoint.fragment,
                                                                     product=t.engagement.product)

                        item.endpoints.add(ep)

                    if item.unsaved_tags is not None:
                        item.tags = item.unsaved_tags

                    finding_count += 1

                messages.add_message(request,
                                     messages.SUCCESS,
                                     scan_type + ' processed, a total of ' + message(finding_count, 'finding',
                                                                                     'processed'),
                                     extra_tags='alert-success')

                create_notification(event='results_added', title='Results added', finding_count=finding_count, test=t, engagement=engagement, url=request.build_absolute_uri(reverse('view_test', args=(t.id,))))

                return HttpResponseRedirect(reverse('view_test', args=(t.id,)))
            except SyntaxError:
                messages.add_message(request,
                                     messages.ERROR,
                                     'There appears to be an error in the XML report, please check and try again.',
                                     extra_tags='alert-danger')

    add_breadcrumb(parent=engagement, title="Import Scan Results", top_level=False, request=request)
    return render(request,
                  'dojo/import_scan_results.html',
                  {'form': form,
                   'eid': engagement.id,
                   })
Пример #32
0
def import_scan_results(request, eid=None, pid=None):
    engagement = None
    form = ImportScanForm()
    cred_form = CredMappingForm()
    finding_count = 0

    if eid:
        engagement = get_object_or_404(Engagement, id=eid)
        cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(engagement=engagement).order_by('cred_id')

    if request.method == "POST":
        form = ImportScanForm(request.POST, request.FILES)
        cred_form = CredMappingForm(request.POST)
        cred_form.fields["cred_user"].queryset = Cred_Mapping.objects.filter(
            engagement=engagement).order_by('cred_id')
        if form.is_valid():
            # Allows for a test to be imported with an engagement created on the fly
            if engagement is None:
                engagement = Engagement()
                product = get_object_or_404(Product, id=pid)
                engagement.name = "AdHoc Import - " + strftime("%a, %d %b %Y %X", timezone.now().timetuple())
                engagement.threat_model = False
                engagement.api_test = False
                engagement.pen_test = False
                engagement.check_list = False
                engagement.target_start = timezone.now().date()
                engagement.target_end = timezone.now().date()
                engagement.product = product
                engagement.active = True
                engagement.status = 'In Progress'
                engagement.save()
            file = request.FILES['file']
            scan_date = form.cleaned_data['scan_date']
            min_sev = form.cleaned_data['minimum_severity']
            active = form.cleaned_data['active']
            verified = form.cleaned_data['verified']

            scan_type = request.POST['scan_type']
            if not any(scan_type in code
                       for code in ImportScanForm.SCAN_TYPE_CHOICES):
                raise Http404()

            tt, t_created = Test_Type.objects.get_or_create(name=scan_type)
            # will save in development environment
            environment, env_created = Development_Environment.objects.get_or_create(
                name="Development")
            t = Test(
                engagement=engagement,
                test_type=tt,
                target_start=scan_date,
                target_end=scan_date,
                environment=environment,
                percent_complete=100)
            t.lead = request.user
            t.full_clean()
            t.save()
            tags = request.POST.getlist('tags')
            ts = ", ".join(tags)
            t.tags = ts

            # Save the credential to the test
            if cred_form.is_valid():
                if cred_form.cleaned_data['cred_user']:
                    # Select the credential mapping object from the selected list and only allow if the credential is associated with the product
                    cred_user = Cred_Mapping.objects.filter(
                        pk=cred_form.cleaned_data['cred_user'].id,
                        engagement=eid).first()

                    new_f = cred_form.save(commit=False)
                    new_f.test = t
                    new_f.cred_id = cred_user.cred_id
                    new_f.save()

            parser = import_parser_factory(file, t)

            try:
                for item in parser.items:
                    print "item blowup"
                    print item
                    sev = item.severity
                    if sev == 'Information' or sev == 'Informational':
                        sev = 'Info'

                    item.severity = sev

                    if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]:
                        continue

                    item.test = t
                    if item.date == timezone.now().date():
                        item.date = t.target_start

                    item.reporter = request.user
                    item.last_reviewed = timezone.now()
                    item.last_reviewed_by = request.user
                    item.active = active
                    item.verified = verified
                    item.save(dedupe_option=False, false_history=True)

                    if hasattr(item, 'unsaved_req_resp') and len(
                            item.unsaved_req_resp) > 0:
                        for req_resp in item.unsaved_req_resp:
                            burp_rr = BurpRawRequestResponse(
                                finding=item,
                                burpRequestBase64=req_resp["req"],
                                burpResponseBase64=req_resp["resp"],
                            )
                            burp_rr.clean()
                            burp_rr.save()

                    if item.unsaved_request is not None and item.unsaved_response is not None:
                        burp_rr = BurpRawRequestResponse(
                            finding=item,
                            burpRequestBase64=item.unsaved_request,
                            burpResponseBase64=item.unsaved_response,
                        )
                        burp_rr.clean()
                        burp_rr.save()

                    for endpoint in item.unsaved_endpoints:
                        ep, created = Endpoint.objects.get_or_create(
                            protocol=endpoint.protocol,
                            host=endpoint.host,
                            path=endpoint.path,
                            query=endpoint.query,
                            fragment=endpoint.fragment,
                            product=t.engagement.product)

                        item.endpoints.add(ep)
                    item.save(false_history=True)

                    if item.unsaved_tags is not None:
                        item.tags = item.unsaved_tags

                    finding_count += 1

                messages.add_message(
                    request,
                    messages.SUCCESS,
                    scan_type + ' processed, a total of ' + message(
                        finding_count, 'finding', 'processed'),
                    extra_tags='alert-success')

                create_notification(
                    event='results_added',
                    title=str(finding_count) + " findings for " + engagement.product.name,
                    finding_count=finding_count,
                    test=t,
                    engagement=engagement,
                    url=request.build_absolute_uri(
                        reverse('view_test', args=(t.id, ))))

                return HttpResponseRedirect(
                    reverse('view_test', args=(t.id, )))
            except SyntaxError:
                messages.add_message(
                    request,
                    messages.ERROR,
                    'There appears to be an error in the XML report, please check and try again.',
                    extra_tags='alert-danger')
    prod_id = None
    custom_breadcrumb = None
    title = "Import Scan Results"
    if engagement:
        prod_id = engagement.product.id
        product_tab = Product_Tab(prod_id, title=title, tab="engagements")
        product_tab.setEngagement(engagement)
    else:
        prod_id = pid
        custom_breadcrumb = {"", ""}
        product_tab = Product_Tab(prod_id, title=title, tab="findings")

    return render(request, 'dojo/import_scan_results.html', {
        'form': form,
        'product_tab': product_tab,
        'custom_breadcrumb': custom_breadcrumb,
        'title': title,
        'cred_form': cred_form,
    })
Пример #33
0
def import_object_eng(request, engagement, json_data):
    create_test_code_review = False
    create_alert = False

    #Get the product from the engagement
    product = engagement.product

    #Retrieve the files currently set for this product
    object_queryset = Objects.objects.filter(
        product=engagement.product.id).order_by('-path')
    data = json.load(json_data)

    #Set default review status
    review_status_id = 1
    review_status = Objects_Review.objects.get(pk=review_status_id)

    for file in data:
        print file["path"]
        #Save the file if the object isn't in object table
        file_type, found_object = find_item(file["path"], object_queryset)

        if found_object is None or file_type == "path":
            review_status_id = 1

            if file_type == "path":
                #Copy the review status
                review_status_id = found_object.review_status.id

            #Set default review status
            review_status = Objects_Review.objects.get(pk=review_status_id)

            #if found_object is None:
            object = Objects(product=product,
                             path=file["path"],
                             review_status=review_status)
            object.save()
            found_object = object
            if file_type == "path":
                for tag in found_object.tags.all():
                    Tag.objects.update_tags(object, tag.name)

        full_url = None
        type = None
        percentUnchanged = None
        build_id = None
        if "full_url" in file:
            full_url = file["full_url"]
        if "type" in file:
            type = file["type"]
        if "percentUnchanged" in file:
            percentUnchanged = file["percentUnchanged"]
        if "build_id" in file:
            build_id = file["build_id"][:12]

        #Find the status so the appropriate action takes place
        if found_object.review_status.id == 2:
            create_alert = True
        elif found_object.review_status.id == 3:
            create_test_code_review = True
            create_alert = True

        #Save the changed files to the engagement view
        object_eng = Objects_Engagement(engagement=engagement,
                                        object_id=found_object,
                                        full_url=full_url,
                                        type=type,
                                        percentUnchanged=percentUnchanged,
                                        build_id=build_id)
        object_eng.save()

    #Create the notification
    if create_alert:
        create_notification(
            event='code_review',
            title='Manual Code Review Requested',
            description=
            "Manual code review requested as tracked file changes were found in the latest build.",
            engagement=engagement,
            url=request.build_absolute_uri(
                reverse('view_object_eng', args=(engagement.id, ))))

    #Create the test within the engagement
    if create_test_code_review:
        environment, env_created = Development_Environment.objects.get_or_create(
            name="Development")
        tt = Test_Type.objects.get(pk=27)  #Manual code review
        if tt:
            test = Test(engagement=engagement,
                        test_type=tt,
                        target_start=timezone.now(),
                        target_end=timezone.now() + timezone.timedelta(days=1),
                        environment=environment,
                        percent_complete=0)
            test.save()
            create_notification(event='test_added',
                                title='Test added for Manual Code Review',
                                test=test,
                                engagement=engagement,
                                url=request.build_absolute_uri(
                                    reverse('view_engagement',
                                            args=(engagement.id, ))))
Пример #34
0
def async_custom_pdf_report(self,
                            report=None,
                            template="None",
                            filename='report.pdf',
                            host=None,
                            user=None,
                            uri=None,
                            finding_notes=False,
                            finding_images=False):
    config = pdfkit.configuration(wkhtmltopdf=settings.WKHTMLTOPDF_PATH)

    selected_widgets = report_widget_factory(json_data=report.options, request=None, user=user,
                                             finding_notes=finding_notes, finding_images=finding_images, host=host)

    widgets = selected_widgets.values()
    temp = None

    try:
        report.task_id = async_custom_pdf_report.request.id
        report.save()

        toc = None
        toc_depth = 4

        if 'table-of-contents' in selected_widgets:
            xsl_style_sheet_tempalte = "dojo/pdf_toc.xsl"
            temp = tempfile.NamedTemporaryFile()

            toc_settings = selected_widgets['table-of-contents']

            toc_depth = toc_settings.depth
            toc_bytes = render_to_string(xsl_style_sheet_tempalte, {'widgets': widgets,
                                                                    'depth': toc_depth,
                                                                    'title': toc_settings.title})
            temp.write(toc_bytes)
            temp.seek(0)

            toc = {'toc-header-text': toc_settings.title,
                   'xsl-style-sheet': temp.name}

        # default the cover to not come first by default
        cover_first_val = False

        cover = None
        if 'cover-page' in selected_widgets:
            cover_first_val = True
            cp = selected_widgets['cover-page']
            x = urlencode({'title': cp.title,
                           'subtitle': cp.sub_heading,
                           'info': cp.meta_info})
            cover = host + reverse(
                'report_cover_page') + "?" + x
        bytes = render_to_string(template, {'widgets': widgets,
                                            'toc_depth': toc_depth,
                                            'host': host,
                                            'report_name': report.name})
        pdf = pdfkit.from_string(bytes,
                                 False,
                                 configuration=config,
                                 toc=toc,
                                 cover=cover,
                                 cover_first=cover_first_val)

        if report.file.name:
            with open(report.file.path, 'w') as f:
                f.write(pdf)
            f.close()
        else:
            f = ContentFile(pdf)
            report.file.save(filename, f)
        report.status = 'success'
        report.done_datetime = timezone.now()
        report.save()

        create_notification(event='report_created', title='Report created', description='The report "%s" is ready.' % report.name, url=uri, report=report, objowner=report.requester)
    except Exception as e:
        report.status = 'error'
        report.save()
        # email_requester(report, uri, error=e)
        # raise e
        log_generic_alert("PDF Report", "Report Creation Failure", "Make sure WKHTMLTOPDF is installed. " + str(e))
    finally:
        if temp is not None:
            # deleting temp xsl file
            temp.close()

    return True
Пример #35
0
def async_docx_report(self,
                      report=None,
                      template="None",
                      filename='report.docx',
                      report_title=None,
                      report_subtitle=None,
                      report_info=None,
                      context={},
                      uri=None):
    def format_fields(tpl):

        context['engagement'].executive_summary = Markdown(
            context['engagement'].executive_summary)
        context['engagement'].technical_summary = Markdown(
            context['engagement'].technical_summary)

        for finding in context['findings']:
            if finding.formatting == 'Markdown':
                format_func = Markdown
            else:
                format_func = RichText

            finding.pics = [
                InlineImage(tpl,
                            settings.MEDIA_ROOT + pic.image.name,
                            width=Mm(150)) for pic in finding.images.all()
            ]

            finding.description = format_func(finding.description)
            finding.impact = format_func(finding.impact)
            finding.mitigation = format_func(finding.mitigation)
            finding.references = format_func(finding.references)

    import sys
    reload(sys)
    sys.setdefaultencoding('utf-8')

    try:
        report.task_id = async_docx_report.request.id
        report.status = 'running'
        report.save()

        d = DocxTemplate(template)
        format_fields(d)
        d.render(context)

        if report.file.name:
            d.save(report.file.path)
        else:
            rtmp = StringIO()
            d.save(rtmp)
            f = ContentFile(rtmp.getvalue())
            report.file.save(filename, f)

        report.status = 'success'
        report.done_datetime = timezone.now()
        report.save()

        create_notification(event='report_created',
                            title='Report created',
                            description='The report "%s" is ready.' %
                            report.name,
                            icon='file-text',
                            url=uri,
                            report=report,
                            objowner=report.requester)
    except Exception as e:
        import traceback
        report.status = 'error'
        report.save()
        exc_type, exc_obj, exc_tb = sys.exc_info()
        traceback.print_tb(exc_tb)
        # print(exc_type, exc_tb.tb_lineno)
        raise e

    return True
Пример #36
0
def log_generic_alert(source, title, description):
    create_notification(event='other', title=title, description=description,
                        icon='bullseye', source=source)
Пример #37
0
def re_import_scan_results(request, tid):
    additional_message = "When re-uploading a scan, any findings not found in original scan will be updated as " \
                         "mitigated.  The process attempts to identify the differences, however manual verification " \
                         "is highly recommended."
    t = get_object_or_404(Test, id=tid)
    scan_type = t.test_type.name
    engagement = t.engagement
    form = ReImportScanForm()

    form.initial['tags'] = [tag.name for tag in t.tags]
    if request.method == "POST":
        form = ReImportScanForm(request.POST, request.FILES)
        if form.is_valid():
            scan_date = form.cleaned_data['scan_date']
            min_sev = form.cleaned_data['minimum_severity']
            file = request.FILES['file']
            scan_type = t.test_type.name
            active = form.cleaned_data['active']
            verified = form.cleaned_data['verified']
            tags = request.POST.getlist('tags')
            ts = ", ".join(tags)
            t.tags = ts
            try:
                parser = import_parser_factory(file, t)
            except ValueError:
                raise Http404()

            try:
                items = parser.items
                original_items = t.finding_set.all().values_list("id", flat=True)
                new_items = []
                mitigated_count = 0
                finding_count = 0
                finding_added_count = 0
                reactivated_count = 0
                for item in items:
                    sev = item.severity
                    if sev == 'Information' or sev == 'Informational':
                        sev = 'Info'

                    if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]:
                        continue

                    if scan_type == 'Veracode Scan' or scan_type == 'Arachni Scan':
                        find = Finding.objects.filter(title=item.title,
                                                      test__id=t.id,
                                                      severity=sev,
                                                      numerical_severity=Finding.get_numerical_severity(sev),
                                                      description=item.description
                                                      )
                    else:
                        find = Finding.objects.filter(title=item.title,
                                                      test__id=t.id,
                                                      severity=sev,
                                                      numerical_severity=Finding.get_numerical_severity(sev),
                                                      )

                    if len(find) == 1:
                        find = find[0]
                        if find.mitigated:
                            # it was once fixed, but now back
                            find.mitigated = None
                            find.mitigated_by = None
                            find.active = True
                            find.verified = verified
                            find.save()
                            note = Notes(entry="Re-activated by %s re-upload." % scan_type,
                                         author=request.user)
                            note.save()
                            find.notes.add(note)
                            reactivated_count += 1
                        new_items.append(find.id)
                    else:
                        item.test = t
                        item.date = t.target_start
                        item.reporter = request.user
                        item.last_reviewed = timezone.now()
                        item.last_reviewed_by = request.user
                        item.verified = verified
                        item.active = active
                        item.save()
                        finding_added_count += 1
                        new_items.append(item.id)
                        find = item

                        if hasattr(item, 'unsaved_req_resp') and len(item.unsaved_req_resp) > 0:
                            for req_resp in item.unsaved_req_resp:
                                burp_rr = BurpRawRequestResponse(finding=find,
                                                                 burpRequestBase64=req_resp["req"],
                                                                 burpResponseBase64=req_resp["resp"],
                                                                 )
                                burp_rr.clean()
                                burp_rr.save()

                        if item.unsaved_request is not None and item.unsaved_response is not None:
                            burp_rr = BurpRawRequestResponse(finding=find,
                                                             burpRequestBase64=item.unsaved_request,
                                                             burpResponseBase64=item.unsaved_response,
                                                             )
                            burp_rr.clean()
                            burp_rr.save()
                    if find:
                        finding_count += 1
                        for endpoint in item.unsaved_endpoints:
                            ep, created = Endpoint.objects.get_or_create(protocol=endpoint.protocol,
                                                                         host=endpoint.host,
                                                                         path=endpoint.path,
                                                                         query=endpoint.query,
                                                                         fragment=endpoint.fragment,
                                                                         product=t.engagement.product)
                            find.endpoints.add(ep)

                        if item.unsaved_tags is not None:
                            find.tags = item.unsaved_tags

                # calculate the difference
                to_mitigate = set(original_items) - set(new_items)
                for finding_id in to_mitigate:
                    finding = Finding.objects.get(id=finding_id)
                    finding.mitigated = datetime.combine(scan_date, timezone.now().time())
                    finding.mitigated_by = request.user
                    finding.active = False
                    finding.save()
                    note = Notes(entry="Mitigated by %s re-upload." % scan_type,
                                 author=request.user)
                    note.save()
                    finding.notes.add(note)
                    mitigated_count += 1
                messages.add_message(request,
                                     messages.SUCCESS,
                                     '%s processed, a total of ' % scan_type + message(finding_count, 'finding',
                                                                                       'processed'),
                                     extra_tags='alert-success')
                if finding_added_count > 0:
                    messages.add_message(request,
                                         messages.SUCCESS,
                                         'A total of ' + message(finding_added_count, 'finding',
                                                                 'added') + ', that are new to scan.',
                                         extra_tags='alert-success')
                if reactivated_count > 0:
                    messages.add_message(request,
                                         messages.SUCCESS,
                                         'A total of ' + message(reactivated_count, 'finding',
                                                                 'reactivated') + ', that are back in scan results.',
                                         extra_tags='alert-success')
                if mitigated_count > 0:
                    messages.add_message(request,
                                         messages.SUCCESS,
                                         'A total of ' + message(mitigated_count, 'finding',
                                                                 'mitigated') + '. Please manually verify each one.',
                                         extra_tags='alert-success')

                create_notification(event='results_added', title='Results added', finding_count=finding_count, test=t, engagement=engagement, url=request.build_absolute_uri(reverse('view_test', args=(t.id,))))

                return HttpResponseRedirect(reverse('view_test', args=(t.id,)))
            except SyntaxError:
                messages.add_message(request,
                                     messages.ERROR,
                                     'There appears to be an error in the XML report, please check and try again.',
                                     extra_tags='alert-danger')

    add_breadcrumb(parent=t, title="Re-upload a %s" % scan_type, top_level=False, request=request)
    return render(request,
                  'dojo/import_scan_results.html',
                  {'form': form,
                   'eid': engagement.id,
                   'additional_message': additional_message,
                   })
Пример #38
0
def async_custom_pdf_report(self,
                            report=None,
                            template="None",
                            filename='report.pdf',
                            host=None,
                            user=None,
                            uri=None,
                            finding_notes=False,
                            finding_images=False):
    config = pdfkit.configuration(wkhtmltopdf=settings.WKHTMLTOPDF_PATH)

    selected_widgets = report_widget_factory(json_data=report.options, request=None, user=user,
                                             finding_notes=finding_notes, finding_images=finding_images, host=host)

    widgets = list(selected_widgets.values())
    temp = None

    try:
        report.task_id = async_custom_pdf_report.request.id
        report.save()

        toc = None
        toc_depth = 4

        if 'table-of-contents' in selected_widgets:
            xsl_style_sheet_tempalte = "dojo/pdf_toc.xsl"
            temp = tempfile.NamedTemporaryFile()

            toc_settings = selected_widgets['table-of-contents']

            toc_depth = toc_settings.depth
            toc_bytes = render_to_string(xsl_style_sheet_tempalte, {'widgets': widgets,
                                                                    'depth': toc_depth,
                                                                    'title': toc_settings.title})
            temp.write(toc_bytes)
            temp.seek(0)

            toc = {'toc-header-text': toc_settings.title,
                   'xsl-style-sheet': temp.name}

        # default the cover to not come first by default
        cover_first_val = False

        cover = None
        if 'cover-page' in selected_widgets:
            cover_first_val = True
            cp = selected_widgets['cover-page']
            x = urlencode({'title': cp.title,
                           'subtitle': cp.sub_heading,
                           'info': cp.meta_info})
            cover = host + reverse(
                'report_cover_page') + "?" + x
        bytes = render_to_string(template, {'widgets': widgets,
                                            'toc_depth': toc_depth,
                                            'host': host,
                                            'report_name': report.name})
        pdf = pdfkit.from_string(bytes,
                                 False,
                                 configuration=config,
                                 toc=toc,
                                 cover=cover,
                                 cover_first=cover_first_val)

        if report.file.name:
            with open(report.file.path, 'w') as f:
                f.write(pdf)
            f.close()
        else:
            f = ContentFile(pdf)
            report.file.save(filename, f)
        report.status = 'success'
        report.done_datetime = timezone.now()
        report.save()

        create_notification(event='report_created', title='Report created', description='The report "%s" is ready.' % report.name, url=uri, report=report, objowner=report.requester)
    except Exception as e:
        report.status = 'error'
        report.save()
        # email_requester(report, uri, error=e)
        # raise e
        log_generic_alert("PDF Report", "Report Creation Failure", "Make sure WKHTMLTOPDF is installed. " + str(e))
    finally:
        if temp is not None:
            # deleting temp xsl file
            temp.close()

    return True
Пример #39
0
def re_import_scan_results(request, tid):
    additional_message = "When re-uploading a scan, any findings not found in original scan will be updated as " \
                         "mitigated.  The process attempts to identify the differences, however manual verification " \
                         "is highly recommended."
    t = get_object_or_404(Test, id=tid)
    scan_type = t.test_type.name
    engagement = t.engagement
    form = ReImportScanForm()

    form.initial['tags'] = [tag.name for tag in t.tags]
    if request.method == "POST":
        form = ReImportScanForm(request.POST, request.FILES)
        if form.is_valid():
            scan_date = form.cleaned_data['scan_date']
            min_sev = form.cleaned_data['minimum_severity']
            file = request.FILES['file']
            scan_type = t.test_type.name
            active = form.cleaned_data['active']
            verified = form.cleaned_data['verified']
            tags = request.POST.getlist('tags')
            ts = ", ".join(tags)
            t.tags = ts
            try:
                parser = import_parser_factory(file, t, active, verified)
            except ValueError:
                raise Http404()

            try:
                items = parser.items
                original_items = t.finding_set.all().values_list("id", flat=True)
                new_items = []
                mitigated_count = 0
                finding_count = 0
                finding_added_count = 0
                reactivated_count = 0
                for item in items:
                    sev = item.severity
                    if sev == 'Information' or sev == 'Informational':
                        sev = 'Info'
                        item.severity = sev

                    if Finding.SEVERITIES[sev] > Finding.SEVERITIES[min_sev]:
                        continue

                    if scan_type == 'Veracode Scan' or scan_type == 'Arachni Scan':
                        find = Finding.objects.filter(title=item.title,
                                                      test__id=t.id,
                                                      severity=sev,
                                                      numerical_severity=Finding.get_numerical_severity(sev),
                                                      description=item.description
                                                      )
                    else:
                        find = Finding.objects.filter(title=item.title,
                                                      test__id=t.id,
                                                      severity=sev,
                                                      numerical_severity=Finding.get_numerical_severity(sev),
                                                      )

                    if len(find) == 1:
                        find = find[0]
                        if find.mitigated:
                            # it was once fixed, but now back
                            find.mitigated = None
                            find.mitigated_by = None
                            find.active = True
                            find.verified = verified
                            find.save()
                            note = Notes(entry="Re-activated by %s re-upload." % scan_type,
                                         author=request.user)
                            note.save()
                            find.notes.add(note)
                            reactivated_count += 1
                        new_items.append(find.id)
                    else:
                        item.test = t
                        item.date = scan_date
                        item.reporter = request.user
                        item.last_reviewed = timezone.now()
                        item.last_reviewed_by = request.user
                        item.verified = verified
                        item.active = active
                        item.save(dedupe_option=False)
                        finding_added_count += 1
                        new_items.append(item.id)
                        find = item

                        if hasattr(item, 'unsaved_req_resp') and len(item.unsaved_req_resp) > 0:
                            for req_resp in item.unsaved_req_resp:
                                if scan_type == "Arachni Scan":
                                    burp_rr = BurpRawRequestResponse(
                                        finding=item,
                                        burpRequestBase64=req_resp["req"],
                                        burpResponseBase64=req_resp["resp"],
                                    )
                                else:
                                    burp_rr = BurpRawRequestResponse(
                                        finding=item,
                                        burpRequestBase64=req_resp["req"].encode("utf-8"),
                                        burpResponseBase64=req_resp["resp"].encode("utf-8"),
                                    )
                                burp_rr.clean()
                                burp_rr.save()

                        if item.unsaved_request is not None and item.unsaved_response is not None:
                            burp_rr = BurpRawRequestResponse(finding=find,
                                                             burpRequestBase64=item.unsaved_request.encode("utf-8"),
                                                             burpResponseBase64=item.unsaved_response.encode("utf-8"),
                                                             )
                            burp_rr.clean()
                            burp_rr.save()
                    if find:
                        finding_count += 1
                        for endpoint in item.unsaved_endpoints:
                            ep, created = Endpoint.objects.get_or_create(protocol=endpoint.protocol,
                                                                         host=endpoint.host,
                                                                         path=endpoint.path,
                                                                         query=endpoint.query,
                                                                         fragment=endpoint.fragment,
                                                                         product=t.engagement.product)
                            find.endpoints.add(ep)

                        if item.unsaved_tags is not None:
                            find.tags = item.unsaved_tags

                    find.save()
                # calculate the difference
                to_mitigate = set(original_items) - set(new_items)
                for finding_id in to_mitigate:
                    finding = Finding.objects.get(id=finding_id)
                    finding.mitigated = datetime.combine(scan_date, timezone.now().time())
                    finding.mitigated_by = request.user
                    finding.active = False
                    finding.save()
                    note = Notes(entry="Mitigated by %s re-upload." % scan_type,
                                 author=request.user)
                    note.save()
                    finding.notes.add(note)
                    mitigated_count += 1
                messages.add_message(request,
                                     messages.SUCCESS,
                                     '%s processed, a total of ' % scan_type + message(finding_count, 'finding',
                                                                                       'processed'),
                                     extra_tags='alert-success')
                if finding_added_count > 0:
                    messages.add_message(request,
                                         messages.SUCCESS,
                                         'A total of ' + message(finding_added_count, 'finding',
                                                                 'added') + ', that are new to scan.',
                                         extra_tags='alert-success')
                if reactivated_count > 0:
                    messages.add_message(request,
                                         messages.SUCCESS,
                                         'A total of ' + message(reactivated_count, 'finding',
                                                                 'reactivated') + ', that are back in scan results.',
                                         extra_tags='alert-success')
                if mitigated_count > 0:
                    messages.add_message(request,
                                         messages.SUCCESS,
                                         'A total of ' + message(mitigated_count, 'finding',
                                                                 'mitigated') + '. Please manually verify each one.',
                                         extra_tags='alert-success')

                create_notification(event='results_added', title=str(finding_count) + " findings for " + engagement.product.name, finding_count=finding_count, test=t, engagement=engagement, url=reverse('view_test', args=(t.id,)))

                return HttpResponseRedirect(reverse('view_test', args=(t.id,)))
            except SyntaxError:
                messages.add_message(request,
                                     messages.ERROR,
                                     'There appears to be an error in the XML report, please check and try again.',
                                     extra_tags='alert-danger')

    product_tab = Product_Tab(engagement.product.id, title="Re-upload a %s" % scan_type, tab="engagements")
    product_tab.setEngagement(engagement)
    return render(request,
                  'dojo/import_scan_results.html',
                  {'form': form,
                   'product_tab': product_tab,
                   'eid': engagement.id,
                   'additional_message': additional_message,
                   })
Пример #40
0
    def import_issues(self, test):

        items = list()

        try:
            product = test.engagement.product
            config = product.sonarqube_product_set.all().first()

            client = SonarQubeAPI(
                tool_config=config.sonarqube_tool_config if config else None)

            if config and config.sonarqube_project_key:
                component = client.get_project(config.sonarqube_project_key)
            else:
                component = client.find_project(product.name)

            issues = client.find_issues(component['key'])
            logging.info('Found {} issues for component {}'.format(
                len(issues), component["key"]))

            for issue in issues:
                status = issue['status']
                from_hotspot = issue.get('fromHotspot', False)

                if self.is_closed(status) or from_hotspot:
                    continue

                type = issue['type']
                title = issue['message']
                component_key = issue['component']
                line = issue.get('line')
                rule_id = issue['rule']
                rule = client.get_rule(rule_id)
                severity = self.convert_sonar_severity(rule['severity'])
                description = self.clean_rule_description_html(
                    rule['htmlDesc'])
                cwe = self.clean_cwe(rule['htmlDesc'])
                references = self.get_references(rule['htmlDesc'])

                sonarqube_issue, _ = Sonarqube_Issue.objects.update_or_create(
                    key=issue['key'],
                    defaults={
                        'status': status,
                        'type': type,
                    })

                # Only assign the SonarQube_issue to the first finding related to the issue
                if Finding.objects.filter(
                        sonarqube_issue=sonarqube_issue).exists():
                    sonarqube_issue = None

                find = Finding(
                    title=title,
                    cwe=cwe,
                    description=description,
                    test=test,
                    severity=severity,
                    references=references,
                    file_path=component_key,
                    line=line,
                    active=True,
                    verified=self.is_confirmed(status),
                    false_p=False,
                    duplicate=False,
                    out_of_scope=False,
                    mitigated=None,
                    mitigation='No mitigation provided',
                    impact="No impact provided",
                    numerical_severity=Finding.get_numerical_severity(
                        severity),
                    static_finding=True,
                    sonarqube_issue=sonarqube_issue,
                )
                items.append(find)

        except Exception as e:
            logger.exception(e)
            create_notification(event='other',
                                title='SonarQube API import issue',
                                description=e,
                                icon='exclamation-triangle',
                                source='SonarQube API')

        return items
Пример #41
0
def log_generic_alert(source, title, description):
    create_notification(event='other', title=title, description=description,
                        icon='bullseye', source=source)
Пример #42
0
    def save(self):
        data = self.validated_data
        skip_duplicates = data['skip_duplicates']
        close_old_findings = data['close_old_findings']
        test_type, created = Test_Type.objects.get_or_create(
            name=data.get('test_type', data['scan_type']))
        environment, created = Development_Environment.objects.get_or_create(
            name='Development')
        test = Test(
            engagement=data['engagement'],
            lead=data['lead'],
            test_type=test_type,
            target_start=data['scan_date'],
            target_end=data['scan_date'],
            environment=environment,
            percent_complete=100)
        try:
            test.full_clean()
        except ValidationError:
            pass

        test.save()
        test.tags = u' '.join(data['tags'])
        try:
            parser = import_parser_factory(data['file'],
                                           test,
                                           data['scan_type'],)
        except ValueError:
            raise Exception('FileParser ValueError')

        skipped_hashcodes = []
        try:
            for item in parser.items:
                if skip_duplicates:
                    hash_code = item.compute_hash_code()
                    if Finding.objects.filter(Q(active=True) | Q(false_p=True) | Q(duplicate=True),
                                              test__engagement__product=test.engagement.product,
                                              hash_code=hash_code).exists():
                        skipped_hashcodes.append(hash_code)
                        continue

                sev = item.severity
                if sev == 'Information' or sev == 'Informational':
                    sev = 'Info'

                item.severity = sev

                if (Finding.SEVERITIES[sev] >
                        Finding.SEVERITIES[data['minimum_severity']]):
                    continue

                item.test = test
                item.date = test.target_start
                item.reporter = self.context['request'].user
                item.last_reviewed = timezone.now()
                item.last_reviewed_by = self.context['request'].user
                item.active = data['active']
                item.verified = data['verified']
                item.save()

                if (hasattr(item, 'unsaved_req_resp') and
                        len(item.unsaved_req_resp) > 0):
                    for req_resp in item.unsaved_req_resp:
                        burp_rr = BurpRawRequestResponse(
                            finding=item,
                            burpRequestBase64=req_resp["req"],
                            burpResponseBase64=req_resp["resp"])
                        burp_rr.clean()
                        burp_rr.save()

                if (item.unsaved_request is not None and
                        item.unsaved_response is not None):
                    burp_rr = BurpRawRequestResponse(
                        finding=item,
                        burpRequestBase64=item.unsaved_request,
                        burpResponseBase64=item.unsaved_response)
                    burp_rr.clean()
                    burp_rr.save()

                for endpoint in item.unsaved_endpoints:
                    ep, created = Endpoint.objects.get_or_create(
                        protocol=endpoint.protocol,
                        host=endpoint.host,
                        path=endpoint.path,
                        query=endpoint.query,
                        fragment=endpoint.fragment,
                        product=test.engagement.product)

                    item.endpoints.add(ep)

                # if item.unsaved_tags is not None:
                #    item.tags = item.unsaved_tags
        except SyntaxError:
            raise Exception('Parser SyntaxError')

        if close_old_findings:
            # Close old active findings that are not reported by this scan.
            new_hash_codes = test.finding_set.values('hash_code')
            for old_finding in Finding.objects.exclude(test=test) \
                                              .exclude(hash_code__in=new_hash_codes) \
                                              .exclude(hash_code__in=skipped_hashcodes) \
                               .filter(test__engagement__product=test.engagement.product,
                                       test__test_type=test_type,
                                       active=True):
                old_finding.active = False
                old_finding.mitigated = datetime.datetime.combine(
                    test.target_start,
                    timezone.now().time())
                old_finding.mitigated_by = self.context['request'].user
                old_finding.notes.create(author=self.context['request'].user,
                                         entry="This finding has been automatically closed"
                                         " as it is not present anymore in recent scans.")
                old_finding.save()
                title = 'An old finding has been closed for "{}".' \
                        .format(test.engagement.product.name)
                description = 'See <a href="{}">{}</a>' \
                        .format(reverse('view_finding', args=(old_finding.id, )),
                                old_finding.title)
                create_notification(event='other',
                                    title=title,
                                    description=description,
                                    icon='bullseye',
                                    objowner=self.context['request'].user)

        return test