From c228b50eeb84558d85a5a630efa30b12b0f1131e Mon Sep 17 00:00:00 2001 From: Yogesh Ojha Date: Tue, 4 Feb 2025 09:51:50 +0530 Subject: [PATCH 1/3] Add permission checks for project deletion and creation in dashboard --- web/dashboard/templates/dashboard/projects.html | 12 +++++++++--- web/dashboard/views.py | 1 + web/reNgine/definitions.py | 2 +- web/templates/base/_items/top_bar.html | 4 +++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/web/dashboard/templates/dashboard/projects.html b/web/dashboard/templates/dashboard/projects.html index 5117e628f..8e98e675d 100644 --- a/web/dashboard/templates/dashboard/projects.html +++ b/web/dashboard/templates/dashboard/projects.html @@ -1,6 +1,8 @@ {% extends 'base/base.html' %} {% load humanize %} {% load static %} +{% load permission_tags %} + {% block title %} Projects @@ -49,7 +51,11 @@
{{project.name}}
{% if current_project.slug == project.slug %} Current Project cannot be deleted. {% else %} - + {% if request.user|can:'modify_targets' %} + + {% else %} + + {% endif %} {% endif %} @@ -69,7 +75,7 @@
{{project.name}}
function delete_project(id, project_name){ const delAPI = "../../delete/project/" + id; swal.queue([{ - title: 'Are you sure you want to delete '+project_name +'?', + title: 'Are you sure you want to delete '+ project_name +'?', text: "You won't be able to revert this, all targets and scan results also will be deleted!", type: 'warning', showCancelButton: true, @@ -94,7 +100,7 @@
{{project.name}}
.catch(function() { swal.insertQueueStep({ type: 'error', - title: 'Oops! Unable to delete the target!' + title: 'Oops! Unable to delete the project!' }) }) } diff --git a/web/dashboard/views.py b/web/dashboard/views.py index 9eaaf58a9..f45646027 100644 --- a/web/dashboard/views.py +++ b/web/dashboard/views.py @@ -295,6 +295,7 @@ def projects(request, slug): return render(request, 'dashboard/projects.html', context) +@has_permission_decorator(PERM_MODIFY_TARGETS, redirect_url=FOUR_OH_FOUR_URL) def delete_project(request, id): obj = get_object_or_404(Project, id=id) if request.method == "POST": diff --git a/web/reNgine/definitions.py b/web/reNgine/definitions.py index abe599156..de9f50be5 100644 --- a/web/reNgine/definitions.py +++ b/web/reNgine/definitions.py @@ -442,7 +442,7 @@ # Roles and Permissions PERM_MODIFY_SYSTEM_CONFIGURATIONS = 'modify_system_configurations' PERM_MODIFY_SCAN_CONFIGURATIONS = 'modify_scan_configurations' -PERM_MODIFY_TARGETS = 'modify_targets' +PERM_MODIFY_TARGETS = 'modify_targets' # projects and targets PERM_MODIFY_SCAN_RESULTS = 'modify_scan_results' PERM_MODIFY_WORDLISTS = 'modify_wordlists' PERM_MODIFY_INTERESTING_LOOKUP = 'modify_interesting_lookup' diff --git a/web/templates/base/_items/top_bar.html b/web/templates/base/_items/top_bar.html index 2859b174e..60f27a30b 100644 --- a/web/templates/base/_items/top_bar.html +++ b/web/templates/base/_items/top_bar.html @@ -35,7 +35,9 @@
Search History
{% endfor %} - Create New Project + {% if request.user|can:'modify_targets' %} + Create New Project + {% endif %} {% if user|can:'modify_targets' or user|can:'modify_scan_configurations' or user|can:'modify_system_configurations' or user|can:'modify_wordlists' %} From 1a9f307be90e4ec15514e4d2003e2233f533e3db Mon Sep 17 00:00:00 2001 From: Yogesh Ojha Date: Tue, 4 Feb 2025 10:05:26 +0530 Subject: [PATCH 2/3] Implement custom permission class for DRF --- web/api/permissions.py | 21 +++++++++++++++++++++ web/api/views.py | 7 +++++-- 2 files changed, 26 insertions(+), 2 deletions(-) create mode 100644 web/api/permissions.py diff --git a/web/api/permissions.py b/web/api/permissions.py new file mode 100644 index 000000000..d4b784875 --- /dev/null +++ b/web/api/permissions.py @@ -0,0 +1,21 @@ +from rest_framework.permissions import BasePermission +from rest_framework.exceptions import PermissionDenied +from rolepermissions.checkers import has_permission + +class HasPermission(BasePermission): + """ + This is a custom permission class for DRF that checks if the user + has the required permission. + Usage in drf views: + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_SCAN_CONFIGURATIONS + """ + + def has_permission(self, request, view): + permission_code = getattr(view, 'permission_required', None) + if not permission_code: + raise PermissionDenied(detail="Permission is not specified for this view.") + + if not has_permission(request.user, permission_code): + raise PermissionDenied(detail="This user does not have enough permissions") + return True \ No newline at end of file diff --git a/web/api/views.py b/web/api/views.py index fcea8abd9..7ab0e366c 100644 --- a/web/api/views.py +++ b/web/api/views.py @@ -19,7 +19,6 @@ from django.core.exceptions import ObjectDoesNotExist from django.core.cache import cache - from dashboard.models import * from recon_note.models import * from reNgine.celery import app @@ -34,7 +33,8 @@ from startScan.models import EndPoint from targetApp.models import * from api.shared_api_tasks import import_hackerone_programs_task, sync_bookmarked_programs_task -from .serializers import * +from api.permissions import * +from api.serializers import * logger = logging.getLogger(__name__) @@ -474,6 +474,9 @@ def get(self, request): class CreateProjectApi(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_TARGETS + def get(self, request): req = self.request project_name = req.query_params.get('name') From fb2b59d5d3a921040f6e6d005aee5fe702f6cfa8 Mon Sep 17 00:00:00 2001 From: Yogesh Ojha Date: Tue, 4 Feb 2025 10:15:22 +0530 Subject: [PATCH 3/3] Add permission checks for various API views to enhance security --- web/api/views.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/web/api/views.py b/web/api/views.py index 7ab0e366c..166e89d1c 100644 --- a/web/api/views.py +++ b/web/api/views.py @@ -333,6 +333,9 @@ def clear_all(self, request): class OllamaManager(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_SYSTEM_CONFIGURATIONS + def get(self, request): """ API to download Ollama Models @@ -918,6 +921,9 @@ def post(self, request): class AddTarget(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_TARGETS + def post(self, request): req = self.request data = req.data @@ -1053,6 +1059,9 @@ def post(self, request): class DeleteMultipleRows(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_TARGETS + def post(self, request): req = self.request data = req.data @@ -1072,6 +1081,9 @@ def post(self, request): class StopScan(APIView): + permission_classes = [HasPermission] + permission_required = PERM_INITATE_SCANS_SUBSCANS + def post(self, request): req = self.request data = req.data @@ -1169,6 +1181,9 @@ def abort_subscan(subscan): class InitiateSubTask(APIView): + permission_classes = [HasPermission] + permission_required = PERM_INITATE_SCANS_SUBSCANS + def post(self, request): req = self.request data = req.data @@ -1188,6 +1203,9 @@ def post(self, request): class DeleteSubdomain(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_SCAN_RESULTS + def post(self, request): req = self.request for id in req.data['subdomain_ids']: @@ -1196,6 +1214,9 @@ def post(self, request): class DeleteVulnerability(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_SCAN_RESULTS + def post(self, request): req = self.request for id in req.data['vulnerability_ids']: @@ -1265,6 +1286,9 @@ def get(self, request): class UninstallTool(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_SYSTEM_CONFIGURATIONS + def get(self, request): req = self.request tool_id = req.query_params.get('tool_id') @@ -1303,6 +1327,9 @@ def get(self, request): class UpdateTool(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_SYSTEM_CONFIGURATIONS + def get(self, request): req = self.request tool_id = req.query_params.get('tool_id') @@ -1335,6 +1362,9 @@ def get(self, request): return Response({'status': False, 'message': str(e)}) class GetExternalToolCurrentVersion(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_SYSTEM_CONFIGURATIONS + def get(self, request): req = self.request # toolname is also the command @@ -1371,6 +1401,9 @@ def get(self, request): class GithubToolCheckGetLatestRelease(APIView): + permission_classes = [HasPermission] + permission_required = PERM_MODIFY_SYSTEM_CONFIGURATIONS + def get(self, request): req = self.request