Skip to content

Commit 474bbab

Browse files
committed
Benchmark support intial sprint, ASVS
1 parent 44047a3 commit 474bbab

File tree

16 files changed

+624
-15
lines changed

16 files changed

+624
-15
lines changed

docs/upgrading.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,4 +169,21 @@ Upgrading to 1.2.8 requires:
169169

170170
3. pip install asteval
171171

172+
4. Complete
173+
174+
Upgrading to DefectDojo Version 1.2.9
175+
------------------------------------
176+
177+
New feature: Benchmarks (OWASP ASVS)
178+
Upgrading to 1.2.9 requires:
179+
180+
1. ./manage.py makemigrations
181+
./manage.py migrate
182+
./manage.py loaddata dojo/fixtures/benchmark_type
183+
./manage.py loaddata dojo/fixtures/benchmark_category
184+
./manage.py loaddata dojo/fixtures/benchmark_requirement
185+
186+
2. ./manage.py collectstatic --noinput
187+
188+
172189
4. Complete

dojo/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Django starts so that shared_task will use this app.
55
from .celery import app as celery_app # noqa
66

7-
__version__ = '1.2.8'
7+
__version__ = '1.2.9'
88
__url__ = 'https://github.com/DefectDojo/django-DefectDojo'
99
__docs__ = 'http://defectdojo.readthedocs.io/'
1010
__demo__ = 'http://defectdojo.pythonanywhere.com/'

dojo/benchmark/__init__.py

Whitespace-only changes.

dojo/benchmark/urls.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from django.conf.urls import url
2+
from django.contrib import admin
3+
from django.apps import apps
4+
import views
5+
6+
urlpatterns = [
7+
url(r'^benchmark/(?P<pid>\d+)/type/(?P<type>\d+)$', views.benchmark_view, name='view_product_benchmark'),
8+
url(r'^benchmark/(?P<pid>\d+)/type/(?P<type>\d+)/category/(?P<cat>\d+)', views.benchmark_view, name='view_product_benchmark')
9+
]

dojo/benchmark/views.py

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# # product
2+
import logging
3+
import sys
4+
import json
5+
import pprint
6+
from datetime import datetime
7+
from math import ceil
8+
9+
from dateutil.relativedelta import relativedelta
10+
from django.conf import settings
11+
from django.contrib import messages
12+
from django.contrib.auth.decorators import user_passes_test
13+
from django.core.exceptions import PermissionDenied
14+
from django.core.urlresolvers import reverse
15+
from django.http import HttpResponseRedirect, StreamingHttpResponse, Http404, HttpResponse
16+
from django.shortcuts import render, get_object_or_404
17+
from django.views.decorators.csrf import csrf_exempt
18+
from django.forms import formset_factory, modelformset_factory, inlineformset_factory
19+
from django.db.models import Count, Q
20+
21+
from dojo.filters import ProductFilter, ProductFindingFilter
22+
from dojo.forms import ProductForm, EngForm, DeleteProductForm, Benchmark_Requirement, Benchmark_Product_SummaryForm
23+
from dojo.models import Notifications, Dojo_User, Benchmark_Type, Benchmark_Category, \
24+
Benchmark_Requirement, Benchmark_Product, Product, Benchmark_Product_Summary
25+
from dojo.utils import get_page_items, add_breadcrumb, get_punchcard_data, handle_uploaded_selenium, get_system_setting
26+
from dojo.forms import NotificationsForm, BenchmarkForm, Benchmark_RequirementForm
27+
from pprint import pprint
28+
29+
logger = logging.getLogger(__name__)
30+
31+
def add_benchmark(queryset, product):
32+
requirements = []
33+
for requirement in queryset:
34+
benchmark_product = Benchmark_Product()
35+
benchmark_product.product = product
36+
benchmark_product.control = requirement
37+
requirements.append(benchmark_product)
38+
39+
try:
40+
Benchmark_Product.objects.bulk_create(requirements)
41+
except:
42+
pass
43+
44+
def return_score(queryset):
45+
asvs_level_1_benchmark = 0
46+
asvs_level_1_score = 0
47+
for item in queryset:
48+
if item["pass_fail"]:
49+
asvs_level_1_score = item["pass_fail__count"]
50+
asvs_level_1_benchmark = asvs_level_1_benchmark + item["pass_fail__count"]
51+
52+
return asvs_level_1_benchmark, asvs_level_1_score
53+
54+
55+
def score_asvs(product, benchmark_type):
56+
#Compliant to ASVS level 1 benchmarks
57+
asvs_level_1 = Benchmark_Product.objects.filter(enabled=True, control__enabled=True, product=product, control__category__type=benchmark_type, control__category__enabled=True, control__level_1=True).values('pass_fail').annotate(Count('pass_fail')).order_by()
58+
59+
asvs_level_1_benchmark, asvs_level_1_score = return_score(asvs_level_1)
60+
61+
#Compliant to ASVS level 2 benchmarks
62+
asvs_level_2 = Benchmark_Product.objects.filter(~Q(control__level_1=True), enabled=True, control__enabled=True, product=product, control__category__type=benchmark_type, control__category__enabled=True, control__level_2=True).values('pass_fail').annotate(Count('pass_fail')).order_by()
63+
64+
asvs_level_2_benchmark, asvs_level_2_score = return_score(asvs_level_2)
65+
66+
#Compliant to ASVS level 3 benchmarks
67+
asvs_level_3 = Benchmark_Product.objects.filter(~Q(control__level_1=True), ~Q(control__level_2=True), enabled=True, control__enabled=True, control__category__enabled=True, product=product, control__category__type=benchmark_type, control__level_3=True).values('pass_fail').annotate(Count('pass_fail')).order_by()
68+
69+
asvs_level_3_benchmark, asvs_level_3_score = return_score(asvs_level_3)
70+
71+
benchmark_product_summary = Benchmark_Product_Summary.objects.get(product=product, benchmark_type=benchmark_type)
72+
73+
benchmark_product_summary.asvs_level_1_benchmark = asvs_level_1_benchmark
74+
benchmark_product_summary.asvs_level_1_score = asvs_level_1_score
75+
benchmark_product_summary.asvs_level_2_benchmark = asvs_level_2_benchmark
76+
benchmark_product_summary.asvs_level_2_score = asvs_level_2_score
77+
benchmark_product_summary.asvs_level_3_benchmark = asvs_level_3_benchmark
78+
benchmark_product_summary.asvs_level_3_score = asvs_level_3_score
79+
80+
benchmark_product_summary.save()
81+
82+
83+
def benchmark_view(request, pid, type, cat=None):
84+
product = get_object_or_404(Product, id=pid)
85+
benchmark_type = get_object_or_404(Benchmark_Type, id=type)
86+
benchmark_category = Benchmark_Category.objects.filter(type=type, enabled=True).order_by('name')
87+
category_name = ""
88+
89+
#Add requirements to the product
90+
add_benchmark(Benchmark_Requirement.objects.filter(category__type=type, category__type__enabled=True, enabled=True).all(), product)
91+
92+
if cat:
93+
category_name = Benchmark_Category.objects.get(id=cat, enabled=True).name
94+
95+
#Create the benchmark summary category
96+
try:
97+
benchmark_product_summary = Benchmark_Product_Summary.objects.get(product=product, benchmark_type=benchmark_type)
98+
except:
99+
pass
100+
benchmark_product_summary = Benchmark_Product_Summary(product=product, benchmark_type=benchmark_type)
101+
benchmark_product_summary.save()
102+
103+
#Insert any new benchmarks since last created
104+
new_benchmarks = Benchmark_Requirement.objects.filter(category__type=type, category__type__enabled=True, enabled=True).exclude(id__in=Benchmark_Product.objects.filter(product=product).values_list('control_id', flat=True))
105+
add_benchmark(new_benchmarks, product)
106+
107+
Benchmark_ProductFormSet = modelformset_factory(Benchmark_Product, exclude=['product, control'], extra=0)
108+
109+
if request.method == 'POST':
110+
form = Benchmark_ProductFormSet(request.POST)
111+
summary_form = Benchmark_Product_SummaryForm(request.POST, instance=benchmark_product_summary)
112+
113+
if form.is_valid():
114+
#print summary_form.errors
115+
summary_form_save = summary_form.save()
116+
form_save = form.save()
117+
score_asvs(product, benchmark_type)
118+
benchmark_product_summary = Benchmark_Product_Summary.objects.get(product=product, benchmark_type=benchmark_type)
119+
120+
messages.add_message(request,
121+
messages.SUCCESS,
122+
'Benchmarks saved.',
123+
extra_tags='alert-success')
124+
125+
add_breadcrumb(title="Benchmarks", top_level=False, request=request)
126+
127+
if cat:
128+
benchmarks = Benchmark_Product.objects.filter(product=product.id, control__category=cat, control__category__enabled=True, control__category__type=type, control__enabled=True).all().order_by('control__objective_number')
129+
130+
benchmark_formset = Benchmark_ProductFormSet(queryset=Benchmark_Product.objects.filter(product=product.id, control__category=cat, control__category__enabled=True, control__category__type=type, control__enabled=True).all().order_by('control__objective_number'))
131+
else:
132+
benchmarks = Benchmark_Product.objects.filter(product=product.id, control__category__enabled=True, control__category__type=type, control__enabled=True).all().order_by('control__category__name', 'control__objective_number')
133+
134+
benchmark_formset = Benchmark_ProductFormSet(queryset=Benchmark_Product.objects.filter(product=product.id, control__category__enabled=True,control__category__type=type, control__enabled=True).all().order_by('control__category__name', 'control__objective_number'))
135+
136+
benchmark_summary_form = Benchmark_Product_SummaryForm(instance=benchmark_product_summary)
137+
138+
return render(request, 'dojo/benchmark.html',
139+
{'benchmarks': benchmarks,
140+
'benchmark_product_summary': benchmark_product_summary,
141+
'benchmark_summary_form': benchmark_summary_form,
142+
'benchmark_formset': benchmark_formset,
143+
'benchmark_type': benchmark_type,
144+
'product': product,
145+
'category_name': category_name,
146+
'benchmark_category': benchmark_category})
147+
148+
149+
@user_passes_test(lambda u: u.is_superuser)
150+
def global_notifications(request):
151+
try:
152+
notifications_obj = Notifications.objects.get(user=None)
153+
except:
154+
notifications_obj = Notifications(user=None)
155+
156+
form = NotificationsForm(instance=notifications_obj)
157+
if request.method == 'POST':
158+
form = NotificationsForm(request.POST, instance=notifications_obj)
159+
if form.is_valid():
160+
new_settings = form.save()
161+
messages.add_message(request,
162+
messages.SUCCESS,
163+
'Settings saved.',
164+
extra_tags='alert-success')
165+
166+
add_breadcrumb(title="Global notification settings", top_level=False, request=request)
167+
return render(request, 'dojo/notifications.html',
168+
{'form': form,
169+
'scope': 'global',
170+
'admin': request.user.is_superuser})

dojo/fixtures/benchmark_category

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

dojo/fixtures/benchmark_requirement

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

dojo/fixtures/benchmark_type

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"model": "dojo.benchmark_type", "pk": 1, "fields": {"name": "OWASP ASVS", "version": "v. 3.1", "benchmark_source": "OWASP ASVS", "created": "2018-04-03T20:05:56.066Z", "updated": "2018-04-03T20:10:06.519Z", "enabled": true}}]

dojo/forms.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020
Check_List, User, Engagement, Test, Test_Type, Notes, Risk_Acceptance, \
2121
Development_Environment, Dojo_User, Scan, Endpoint, Stub_Finding, Finding_Template, Report, FindingImage, \
2222
JIRA_Issue, JIRA_PKey, JIRA_Conf, UserContactInfo, Tool_Type, Tool_Configuration, Tool_Product_Settings, \
23-
Cred_User, Cred_Mapping, System_Settings, Notifications, Languages, Language_Type, App_Analysis, Objects
23+
Cred_User, Cred_Mapping, System_Settings, Notifications, Languages, Language_Type, App_Analysis, Objects, \
24+
Benchmark_Product, Benchmark_Requirement, Benchmark_Product_Summary
2425
from dojo.utils import get_system_setting
2526

2627
RE_DATE = re.compile(r'(\d{4})-(\d\d?)-(\d\d?)$')
@@ -1289,6 +1290,12 @@ class Meta:
12891290
model = JIRA_Conf
12901291
exclude = ['product']
12911292

1293+
class Benchmark_Product_SummaryForm(forms.ModelForm):
1294+
1295+
class Meta:
1296+
model = Benchmark_Product_Summary
1297+
exclude = ['product', 'current_level', 'benchmark_type', 'asvs_level_1_benchmark', 'asvs_level_1_score', 'asvs_level_2_benchmark', 'asvs_level_2_score', 'asvs_level_3_benchmark', 'asvs_level_3_score']
1298+
12921299
class JIRA_PKeyForm(forms.ModelForm):
12931300

12941301
class Meta:
@@ -1431,6 +1438,18 @@ class Meta:
14311438
model = System_Settings
14321439
exclude = ['product_grade']
14331440

1441+
class BenchmarkForm(forms.ModelForm):
1442+
1443+
class Meta:
1444+
model = Benchmark_Product
1445+
exclude = ['product', 'control']
1446+
1447+
class Benchmark_RequirementForm(forms.ModelForm):
1448+
1449+
class Meta:
1450+
model = Benchmark_Requirement
1451+
exclude = ['']
1452+
14341453
class NotificationsForm(forms.ModelForm):
14351454

14361455
class Meta:

0 commit comments

Comments
 (0)