Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions dojo/announcement/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,13 @@
from django.utils.translation import gettext
from django.utils.translation import gettext_lazy as _

from dojo.authorization.authorization_decorators import (
user_is_configuration_authorized,
)
from dojo.forms import AnnouncementCreateForm, AnnouncementRemoveForm
from dojo.models import Announcement, UserAnnouncement
from dojo.utils import add_breadcrumb

logger = logging.getLogger(__name__)


@user_is_configuration_authorized("dojo.change_announcement")
def configure_announcement(request):
remove = False
if request.method == "GET":
Expand Down
16 changes: 9 additions & 7 deletions dojo/api_v2/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@
import dojo.finding.helper as finding_helper
import dojo.risk_acceptance.helper as ra_helper
from dojo.authorization.authorization import user_has_permission
from dojo.authorization.models import (
Dojo_Group_Member,
Global_Role,
Product_Group,
Product_Member,
Product_Type_Group,
Product_Type_Member,
Role,
)
from dojo.authorization.roles_permissions import Permissions
from dojo.celery_dispatch import dojo_dispatch_task
from dojo.endpoint.utils import endpoint_filter, endpoint_meta_import
Expand Down Expand Up @@ -61,7 +70,6 @@
Cred_User,
Development_Environment,
Dojo_Group,
Dojo_Group_Member,
Dojo_User,
DojoMeta,
Endpoint,
Expand All @@ -75,7 +83,6 @@
Finding_Group,
Finding_Template,
General_Survey,
Global_Role,
Language_Type,
Languages,
Network_Locations,
Expand All @@ -86,15 +93,10 @@
Notifications,
Product,
Product_API_Scan_Configuration,
Product_Group,
Product_Member,
Product_Type,
Product_Type_Group,
Product_Type_Member,
Question,
Regulation,
Risk_Acceptance,
Role,
SLA_Configuration,
Sonarqube_Issue,
Sonarqube_Issue_Transition,
Expand Down
18 changes: 10 additions & 8 deletions dojo/api_v2/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,21 @@
mixins as dojo_mixins,
)
from dojo.api_v2 import (
permissions,
prefetch,
serializers,
)
from dojo.api_v2.prefetch.prefetcher import _Prefetcher
from dojo.authorization import api_permissions as permissions
from dojo.authorization.authorization import user_has_permission_or_403
from dojo.authorization.models import (
Dojo_Group_Member,
Global_Role,
Product_Group,
Product_Member,
Product_Type_Group,
Product_Type_Member,
Role,
)
from dojo.authorization.roles_permissions import Permissions
from dojo.celery_dispatch import dojo_dispatch_task
from dojo.cred.queries import get_authorized_cred_mappings
Expand Down Expand Up @@ -100,7 +109,6 @@
Cred_User,
Development_Environment,
Dojo_Group,
Dojo_Group_Member,
Dojo_User,
DojoMeta,
Endpoint,
Expand All @@ -112,7 +120,6 @@
Finding,
Finding_Template,
General_Survey,
Global_Role,
Language_Type,
Languages,
Network_Locations,
Expand All @@ -123,15 +130,10 @@
Notifications,
Product,
Product_API_Scan_Configuration,
Product_Group,
Product_Member,
Product_Type,
Product_Type_Group,
Product_Type_Member,
Question,
Regulation,
Risk_Acceptance,
Role,
SLA_Configuration,
Sonarqube_Issue,
Sonarqube_Issue_Transition,
Expand Down
6 changes: 4 additions & 2 deletions dojo/asset/api/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field

from dojo.authorization.models import (
Product_Group,
Product_Member,
)
from dojo.filters import (
CharFieldFilterANDExpression,
CharFieldInFilter,
Expand All @@ -16,8 +20,6 @@
from dojo.models import (
Product,
Product_API_Scan_Configuration,
Product_Group,
Product_Member,
)

labels = get_labels()
Expand Down
6 changes: 4 additions & 2 deletions dojo/asset/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@

from dojo.api_v2.serializers import ProductMetaSerializer, TagListSerializerField
from dojo.authorization.authorization import user_has_permission
from dojo.authorization.models import (
Product_Group,
Product_Member,
)
from dojo.authorization.roles_permissions import Permissions
from dojo.models import (
Dojo_User,
Product,
Product_API_Scan_Configuration,
Product_Group,
Product_Member,
)
from dojo.organization.api.serializers import RelatedOrganizationField
from dojo.product.queries import get_authorized_products
Expand Down
9 changes: 6 additions & 3 deletions dojo/asset/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from rest_framework.response import Response

import dojo.api_v2.mixins as dojo_mixins
from dojo.api_v2 import permissions, prefetch
from dojo.api_v2 import prefetch
from dojo.api_v2.serializers import ReportGenerateOptionSerializer, ReportGenerateSerializer
from dojo.api_v2.views import PrefetchDojoModelViewSet, report_generate, schema_with_prefetch
from dojo.asset.api import serializers
Expand All @@ -16,12 +16,15 @@
AssetGroupFilterSet,
AssetMemberFilterSet,
)
from dojo.authorization import api_permissions as permissions
from dojo.authorization.models import (
Product_Group,
Product_Member,
)
from dojo.authorization.roles_permissions import Permissions
from dojo.models import (
Product,
Product_API_Scan_Configuration,
Product_Group,
Product_Member,
)
from dojo.product.queries import (
get_authorized_product_api_scan_configurations,
Expand Down
11 changes: 11 additions & 0 deletions dojo/authorization/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Import query_registrations to trigger RBAC filter registration at startup
from dojo.authorization import query_registrations # noqa: F401
from dojo.authorization.authorization import ( # noqa: F401
user_has_configuration_permission,
user_has_global_permission,
user_has_global_permission_or_403,
user_has_permission,
user_has_permission_or_403,
user_is_superuser_or_global_owner,
)
from dojo.authorization.roles_permissions import Permissions, Roles # noqa: F401
Original file line number Diff line number Diff line change
Expand Up @@ -1285,3 +1285,41 @@ class UserHasConfigurationPermissionSuperuser(

def has_permission(self, request, view):
return super().has_permission(request, view)


class LocationFindingReferencePermission(permissions.BasePermission):
def has_permission(self, request, view):
return check_post_permission(
request,
Finding,
"finding",
Permissions.Finding_Edit,
)

def has_object_permission(self, request, view, obj):
return check_object_permission(
request,
obj.finding,
Permissions.Finding_View,
Permissions.Finding_Edit,
Permissions.Finding_Edit,
)


class LocationProductReferencePermission(permissions.BasePermission):
def has_permission(self, request, view):
return check_post_permission(
request,
Product,
"product",
Permissions.Product_Edit,
)

def has_object_permission(self, request, view, obj):
return check_object_permission(
request,
obj.product,
Permissions.Product_View,
Permissions.Product_Edit,
Permissions.Product_Edit,
)
12 changes: 7 additions & 5 deletions dojo/authorization/authorization.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
from django.core.exceptions import PermissionDenied
from django.db.models import Model, QuerySet

from dojo.authorization.models import (
Dojo_Group_Member,
Product_Group,
Product_Member,
Product_Type_Group,
Product_Type_Member,
)
from dojo.authorization.roles_permissions import (
Permissions,
Roles,
Expand All @@ -12,7 +19,6 @@
App_Analysis,
Cred_Mapping,
Dojo_Group,
Dojo_Group_Member,
Dojo_User,
Endpoint,
Engagement,
Expand All @@ -21,11 +27,7 @@
Languages,
Product,
Product_API_Scan_Configuration,
Product_Group,
Product_Member,
Product_Type,
Product_Type_Group,
Product_Type_Member,
Risk_Acceptance,
Stub_Finding,
Test,
Expand Down
50 changes: 50 additions & 0 deletions dojo/authorization/middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
from django.core.exceptions import PermissionDenied
from django.shortcuts import get_object_or_404

from dojo.authorization.authorization import (
user_has_configuration_permission,
user_has_global_permission_or_403,
user_has_permission_or_403,
)
from dojo.authorization.url_permissions import URL_PERMISSIONS


class AuthorizationMiddleware:
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
return self.get_response(request)

def process_view(self, request, view_func, view_args, view_kwargs):
# Skip API paths -- DRF has its own permission classes
if request.path.startswith("/api/"):
return

resolver_match = request.resolver_match
if resolver_match is None:
return

url_name = resolver_match.url_name
checks = URL_PERMISSIONS.get(url_name)
if not checks:
return

for check in checks:
check_type = check[0]
if check_type == "global":
_, permission = check
user_has_global_permission_or_403(request.user, permission)
elif check_type == "config":
_, permission = check
if not user_has_configuration_permission(request.user, permission):
raise PermissionDenied
elif check_type == "object":
_, model, permission, arg_name = check
lookup_value = view_kwargs.get(arg_name)
if lookup_value is None:
continue # kwarg not present, skip this check
obj = get_object_or_404(model, pk=lookup_value)
user_has_permission_or_403(request.user, obj, permission)

return
68 changes: 68 additions & 0 deletions dojo/authorization/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
from django.db import models
from django.utils.translation import gettext_lazy as _


class Role(models.Model):
name = models.CharField(max_length=255, unique=True)
is_owner = models.BooleanField(default=False)

class Meta:
app_label = "dojo"
ordering = ("name",)

def __str__(self):
return self.name


class Dojo_Group_Member(models.Model):
group = models.ForeignKey("dojo.Dojo_Group", on_delete=models.CASCADE)
user = models.ForeignKey("dojo.Dojo_User", on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.CASCADE, help_text=_("This role determines the permissions of the user to manage the group."), verbose_name=_("Group role"))

class Meta:
app_label = "dojo"


class Global_Role(models.Model):
user = models.OneToOneField("dojo.Dojo_User", null=True, blank=True, on_delete=models.CASCADE)
group = models.OneToOneField("dojo.Dojo_Group", null=True, blank=True, on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.CASCADE, null=True, blank=True, help_text=_("The global role will be applied to all product types and products."), verbose_name=_("Global role"))

class Meta:
app_label = "dojo"


class Product_Member(models.Model):
product = models.ForeignKey("dojo.Product", on_delete=models.CASCADE)
user = models.ForeignKey("dojo.Dojo_User", on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.CASCADE)

class Meta:
app_label = "dojo"


class Product_Group(models.Model):
product = models.ForeignKey("dojo.Product", on_delete=models.CASCADE)
group = models.ForeignKey("dojo.Dojo_Group", on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.CASCADE)

class Meta:
app_label = "dojo"


class Product_Type_Member(models.Model):
product_type = models.ForeignKey("dojo.Product_Type", on_delete=models.CASCADE)
user = models.ForeignKey("dojo.Dojo_User", on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.CASCADE)

class Meta:
app_label = "dojo"


class Product_Type_Group(models.Model):
product_type = models.ForeignKey("dojo.Product_Type", on_delete=models.CASCADE)
group = models.ForeignKey("dojo.Dojo_Group", on_delete=models.CASCADE)
role = models.ForeignKey(Role, on_delete=models.CASCADE)

class Meta:
app_label = "dojo"
Loading
Loading