Skip to content

Commit d7e58d0

Browse files
committed
gut RBAC isinstance / queryset fallbacks from OS auth core
OS authorization now uses only is_superuser / is_staff / authorized_users: - dojo/authorization/authorization.py: drop the Product_Member / Product_Type_Member / Product_Group / Product_Type_Group / Dojo_Group / Dojo_Group_Member isinstance branches in user_has_permission and _user_authorized_for. Drop the get_product_member, get_product_groups, get_product_type_member, get_product_type_groups, get_groups, get_group_member, get_group_members_dict, get_roles_for_permission, role_has_permission, role_has_global_permission backward-compat stubs (none of OS or Pro consumed them). Drop the now-unused RBAC model imports and the QuerySet typing import. - dojo/authorization/query_registrations.py: drop every RBAC-carrier filter registration (members_for_product, groups_for_product, global_members_for_product, product_members, product_groups, product_type_members, product_type_groups, group_members, etc.) and the _carrier_queryset helper that fed them. Pro registers Pro-side implementations of the same hook keys at startup. Pro continues to shadow user_has_permission / user_has_configuration_permission / user_has_global_permission via pro/apps.py:_shadow_authorization_symbols, so Pro deployments keep their full RBAC behavior. OS-only deployments now return False for any non-superuser / non-staff request that doesn't satisfy the authorized_users hierarchy — same as the pre-RBAC OS model.
1 parent 69050f8 commit d7e58d0

2 files changed

Lines changed: 20 additions & 343 deletions

File tree

dojo/authorization/authorization.py

Lines changed: 13 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,25 @@
11
"""
2-
Legacy authorization checks.
2+
OS authorization: is_superuser / is_staff / authorized_users.
33
4-
The hierarchical RBAC role system has been replaced with the simpler
5-
pre-2020 model: a user is authorized for an action on an object iff
4+
The hierarchical RBAC role system has been moved out of OS to the dojo-pro
5+
plugin. OS-only deployments authorize an action on an object iff
66
77
* the user is a superuser, or
8-
* the user is staff and the action is non-destructive
9-
(View / Edit / Add / Import; Delete and member-management require explicit
10-
staff confirmation but legacy treats every staff user as eligible), or
8+
* the user is staff and the action is non-destructive (legacy treats
9+
every staff user as eligible for staff-only and delete actions), or
1110
* the user is in the relevant ``authorized_users`` ManyToMany
1211
(climbing the Product_Type → Product → Engagement → Test → Finding
1312
hierarchy until an explicit membership is found).
1413
1514
Per-product role granularity (Reader / Writer / Maintainer / Owner),
16-
group-level authorization, and configuration permissions per add/edit/delete
17-
codename are not present in this model. Deployments that need that fidelity
18-
should run the dojo-pro plugin, which keeps the RBAC layer alive and shadows
19-
this module's symbols at startup so the same code paths route through Pro.
20-
21-
The public surface (function names + signatures) is preserved so existing
22-
callers in dojo/views.py, dojo/forms.py, etc. keep compiling. Track B step
23-
#13 simplifies callers to pass action strings directly; until that lands,
24-
the existing ``Permissions.X`` enum members are still accepted and reduced
25-
to a legacy Action via ``permission_to_action()``.
15+
group-level authorization, and Member/Group/Role tables are not consulted
16+
in this model. Deployments that need that fidelity should run the
17+
dojo-pro plugin, which keeps the RBAC layer alive and shadows this
18+
module's symbols at startup so the same code paths route through Pro.
2619
"""
2720
from django.core.exceptions import PermissionDenied
28-
from django.db.models import Model, QuerySet
29-
30-
from dojo.authorization.models import (
31-
Dojo_Group_Member,
32-
Product_Group,
33-
Product_Member,
34-
Product_Type_Group,
35-
Product_Type_Member,
36-
)
21+
from django.db.models import Model
22+
3723
from dojo.authorization.roles_permissions import (
3824
Action,
3925
permission_to_action,
@@ -42,7 +28,6 @@
4228
from dojo.models import (
4329
App_Analysis,
4430
Cred_Mapping,
45-
Dojo_Group,
4631
Dojo_User,
4732
Endpoint,
4833
Engagement,
@@ -106,10 +91,8 @@ def user_has_permission(user: Dojo_User, obj: Model, permission) -> bool:
10691
dojo/user/helper.py at commit e7805aa14~ for the historical
10792
reference.
10893
109-
The Member / Group / Cred_Mapping / etc. carrier objects don't expose
110-
authorized_users themselves; they delegate to their wrapped product
111-
or product type, except for self-removal (a user is always allowed to
112-
delete their own membership row).
94+
Cred_Mapping and other carrier objects don't expose authorized_users
95+
themselves; they delegate to their wrapped product or product type.
11396
"""
11497
if not user or getattr(user, "is_anonymous", False):
11598
return False
@@ -124,10 +107,6 @@ def user_has_permission(user: Dojo_User, obj: Model, permission) -> bool:
124107
if action in {Action.StaffOnly, Action.Delete}:
125108
return bool(user.is_staff)
126109

127-
# Member/group self-deletion: any user can remove their own membership
128-
if isinstance(obj, Product_Type_Member | Product_Member | Dojo_Group_Member) and obj.user_id == user.id:
129-
return True
130-
131110
return _user_authorized_for(user, obj, action)
132111

133112

@@ -181,16 +160,6 @@ def _user_authorized_for(user: Dojo_User, obj: Model, action: Action) -> bool:
181160
if isinstance(obj, Endpoint | Languages | App_Analysis | Product_API_Scan_Configuration):
182161
return _user_authorized_for(user, obj.product, action)
183162

184-
if isinstance(obj, Product_Type_Member | Product_Type_Group):
185-
return _user_authorized_for(user, obj.product_type, action)
186-
187-
if isinstance(obj, Product_Member | Product_Group):
188-
return _user_authorized_for(user, obj.product, action)
189-
190-
if isinstance(obj, Dojo_Group | Dojo_Group_Member):
191-
# Group authorization is staff-only in legacy; non-staff already filtered out.
192-
return bool(user.is_staff)
193-
194163
if isinstance(obj, Cred_Mapping):
195164
if obj.product_id:
196165
return _user_authorized_for(user, obj.product, action)
@@ -244,25 +213,6 @@ def user_has_global_permission_or_403(user: Dojo_User, permission) -> None:
244213
raise PermissionDenied
245214

246215

247-
# ---------------------------------------------------------------------------
248-
# Backward-compat shims for the role hierarchy. Legacy authorization does not
249-
# branch on roles, but call sites still import these symbols. Returning empty
250-
# results keeps them harmless until Track B step #13 simplifies the callers.
251-
# ---------------------------------------------------------------------------
252-
253-
254-
def get_roles_for_permission(permission) -> set[int]:
255-
return set()
256-
257-
258-
def role_has_permission(role: int, permission) -> bool:
259-
return False
260-
261-
262-
def role_has_global_permission(role: int, permission) -> bool:
263-
return False
264-
265-
266216
class NoAuthorizationImplementedError(Exception):
267217
def __init__(self, message):
268218
self.message = message
@@ -276,56 +226,3 @@ def __init__(self, message):
276226
class RoleDoesNotExistError(Exception):
277227
def __init__(self, message):
278228
self.message = message
279-
280-
281-
# ---------------------------------------------------------------------------
282-
# RBAC member / group lookup helpers. These return empty/None under legacy —
283-
# the underlying tables (Product_Member, Product_Type_Member, etc.) still
284-
# exist in the database, but legacy authorization does not consult them.
285-
# Track B step #13 will remove call sites; until then these stubs prevent
286-
# AttributeError / TypeError in transitional code.
287-
# ---------------------------------------------------------------------------
288-
289-
290-
def get_product_member(user: Dojo_User, product: Product) -> Product_Member | None:
291-
return None
292-
293-
294-
def get_product_member_dict(user: Dojo_User) -> dict[int, Product_Member]:
295-
return {}
296-
297-
298-
def get_product_type_member(user: Dojo_User, product_type: Product_Type) -> Product_Type_Member | None:
299-
return None
300-
301-
302-
def get_product_type_member_dict(user: Dojo_User) -> dict[int, Product_Type_Member]:
303-
return {}
304-
305-
306-
def get_product_groups(user: Dojo_User, product: Product) -> list[Product_Group]:
307-
return []
308-
309-
310-
def get_product_groups_dict(user: Dojo_User) -> dict[int, list[Product_Group]]:
311-
return {}
312-
313-
314-
def get_product_type_groups(user: Dojo_User, product_type: Product_Type) -> list[Product_Type_Group]:
315-
return []
316-
317-
318-
def get_product_type_groups_dict(user: Dojo_User) -> dict[int, list[Product_Type_Group]]:
319-
return {}
320-
321-
322-
def get_groups(user: Dojo_User) -> QuerySet[Dojo_Group]:
323-
return Dojo_Group.objects.none()
324-
325-
326-
def get_group_member(user: Dojo_User, group: Dojo_Group) -> Dojo_Group_Member | None:
327-
return None
328-
329-
330-
def get_group_members_dict(user: Dojo_User) -> dict[int, Dojo_Group_Member]:
331-
return {}

0 commit comments

Comments
 (0)