|
2 | 2 | title: 'Upgrading to DefectDojo Version 2.58.x' |
3 | 3 | toc_hide: true |
4 | 4 | weight: -20260504 |
5 | | -description: Legacy authorization UI / API rewrite (Open Source); Notification .tpl templates relocated under dojo/notifications/ |
| 5 | +description: Authorized Users panel replaces Members/Groups under legacy authorization; Notification .tpl templates relocated under dojo/notifications/ |
6 | 6 | --- |
7 | 7 |
|
8 | | -## Legacy authorization rewrite — UI and API |
| 8 | +## Authorized Users panel replaces Members/Groups under legacy authorization |
9 | 9 |
|
10 | | -DefectDojo Open Source uses the legacy (pre-2020) authorization model: |
11 | | -access to a Product is granted by `Product.authorized_users` (with cascade |
12 | | -via `Product_Type.authorized_users`), and `is_staff` / `is_superuser` bypass |
13 | | -everything. The RBAC tables (`Product_Member`, `Product_Type_Member`, |
14 | | -`Product_Group`, `Product_Type_Group`, `Dojo_Group_Member`, `Global_Role`) |
15 | | -remain in the schema for forward-compatibility with DefectDojo Pro but are |
16 | | -inert in OS deployments. |
17 | | - |
18 | | -Prior to 2.58, the classic Django-template UI and the v2 REST API still |
19 | | -surfaced these inert RBAC tables — Members/Groups panels that always |
20 | | -returned "No members found", "Add Users" hamburgers that wrote `Product_Member` |
21 | | -rows nobody consulted, role dropdowns, etc. The 2.58 rewrite aligns the UI |
22 | | -and API with the legacy contract: surfaces that drive `authorized_users` |
23 | | -stay (or get added), surfaces that drive RBAC tables are stripped from OS |
24 | | -and exposed as `{% block %}` hooks for Pro to override. All template |
25 | | -changes apply to **both** the Bootstrap (Classic) and Tailwind opt-in UI |
26 | | -trees. |
27 | | - |
28 | | -### Authorized Users panel on Product and Product Type detail |
29 | | - |
30 | | -Replaces the inert Members/Groups panels on `view_product_details.html` and |
31 | | -`view_product_type.html`. The new panel reads from and writes to |
32 | | -`Product.authorized_users` / `Product_Type.authorized_users` directly. |
33 | | - |
34 | | -New endpoints (gated on `Permissions.Product_Manage_Members` / |
35 | | -`Permissions.Product_Type_Manage_Members`, which under legacy map to |
36 | | -`Action.StaffOnly`): |
37 | | - |
38 | | -| Method | Path | Action | |
39 | | -| --- | --- | --- | |
40 | | -| GET/POST | `/product/<pid>/authorized_users/add` | List form / add users to `authorized_users` | |
41 | | -| POST | `/product/<pid>/authorized_users/<user_id>/delete` | Remove user | |
42 | | -| GET/POST | `/product/type/<ptid>/authorized_users/add` | Same for `Product_Type.authorized_users` | |
43 | | -| POST | `/product/type/<ptid>/authorized_users/<user_id>/delete` | Remove user | |
44 | | - |
45 | | -The old `add_product_member` / `add_product_type_member` URLs and views |
46 | | -still exist (Pro uses them) but no longer have an OS UI entry. |
47 | | - |
48 | | -### View User read-only access listing + legacy authorize/revoke |
49 | | - |
50 | | -The "Product Types this User can access" and "Products this User can |
51 | | -access" panels on `/user/<id>/` now iterate `authorized_users`-backed data |
52 | | -under OS: |
53 | | - |
54 | | -* Listing: `Product_Type.objects.filter(authorized_users=user)` and the |
55 | | - product cascade (direct membership *or* product_type membership). |
56 | | -* Add hamburger (staff only) → multi-select form, **no role dropdown**. |
57 | | -* Per-row trash button (staff only) → revokes the user from the row's |
58 | | - `authorized_users` (no `Product_Member` writes). |
59 | | - |
60 | | -New endpoints (all gated on `is_staff`): |
61 | | - |
62 | | -| Method | Path | Action | |
63 | | -| --- | --- | --- | |
64 | | -| GET/POST | `/user/<uid>/authorize_products` | Add user to one or more `Product.authorized_users` | |
65 | | -| GET/POST | `/user/<uid>/authorize_product_types` | Add user to one or more `Product_Type.authorized_users` | |
66 | | -| POST | `/user/<uid>/revoke_product/<pid>` | Remove user from `product.authorized_users` | |
67 | | -| POST | `/user/<uid>/revoke_product_type/<ptid>` | Remove user from `product_type.authorized_users` | |
68 | | - |
69 | | -The OS forms have no role field. Under legacy, access is binary |
70 | | -membership; "role" is RBAC-only. |
71 | | - |
72 | | -### Stripped RBAC surfaces (now `{% block %}` hooks) |
73 | | - |
74 | | -The following RBAC-only UI is removed from OS templates and replaced with |
75 | | -empty `{% block %}` placeholders that Pro overrides via |
76 | | -`pro/templates/dojo/...`: |
77 | | - |
78 | | -| Template | Block(s) | |
79 | | -| --- | --- | |
80 | | -| `view_product_details.html` | `rbac_members_panel`, `rbac_groups_panel` | |
81 | | -| `view_product_type.html` | `rbac_members_panel`, `rbac_groups_panel` | |
82 | | -| `base.html` (left nav, "Users" dropdown) | `groups_submenu_link` | |
83 | | -| `view_user.html` (RBAC view) | `user_product_types_panel`, `user_products_panel`, `user_groups_panel` | |
84 | | -| `profile.html` (Global Role fieldset + Groups) | `global_role_form`, `profile_groups_panel` | |
85 | | -| `add_user.html` (Global Role fieldset) | `global_role_form` | |
86 | | - |
87 | | -Re-apply any in-tree patch / Docker mount overrides against the new block |
88 | | -structure. |
89 | | - |
90 | | -### System Settings — RBAC defaults removed |
91 | | - |
92 | | -`SystemSettingsForm` and `SystemSettingsSerializer` now `Meta.exclude` the |
93 | | -three RBAC-only auto-assignment fields: |
94 | | - |
95 | | -* `default_group` |
96 | | -* `default_group_role` |
97 | | -* `default_group_email_pattern` |
98 | | - |
99 | | -These auto-add new users to a `Dojo_Group` at login — `Dojo_Group_Member` |
100 | | -is inert under legacy, so the fields drove nothing. The model fields |
101 | | -remain so Pro can subclass the form/serializer to re-add them. |
102 | | - |
103 | | -### V2 REST API — RBAC endpoints removed from OS |
104 | | - |
105 | | -Eight RBAC `v2_api.register(...)` calls in `dojo/urls.py` and four alias |
106 | | -registrations in `dojo/asset/api/urls.py` / `dojo/organization/api/urls.py` |
107 | | -are removed. ViewSets and serializers stay in `dojo/api_v2/{views,serializers}.py` |
108 | | -so Pro can keep subclassing them. |
109 | | - |
110 | | -| Removed prefix | Pro replacement | |
111 | | -| --- | --- | |
112 | | -| `/api/v2/dojo_groups/` | `pro/groups` | |
113 | | -| `/api/v2/dojo_group_members/` | `pro/group_members` | |
114 | | -| `/api/v2/global_roles/` | `pro/global_roles` | |
115 | | -| `/api/v2/product_groups/` | `pro/product_groups` | |
116 | | -| `/api/v2/product_members/` | `pro/product_members` | |
117 | | -| `/api/v2/product_type_groups/` | `pro/product_type_groups` | |
118 | | -| `/api/v2/product_type_members/` | `pro/product_type_members` | |
119 | | -| `/api/v2/roles/` | `pro/roles` | |
120 | | -| `/api/v2/asset_groups/`, `/api/v2/asset_members/` | (Removed; aliases for `product_groups` / `product_members`) | |
121 | | -| `/api/v2/organization_groups/`, `/api/v2/organization_members/` | (Removed; aliases for `product_type_groups` / `product_type_members`) | |
122 | | - |
123 | | -The corresponding test classes were removed from |
124 | | -`unittests/test_rest_framework.py`; equivalent coverage lives in |
125 | | -`dojo-pro/dojo-pro/unit_tests/api/<endpoint>/`. |
126 | | - |
127 | | -**Required action for OS API consumers:** if you call any of the removed |
128 | | -endpoints, you have three options: (1) install Pro, which re-registers |
129 | | -all eight, (2) drive access exclusively through |
130 | | -`/api/v2/users/` writes to `is_staff` plus the new |
131 | | -`Product.authorized_users` / `Product_Type.authorized_users` endpoints |
132 | | -above, or (3) maintain a local fork that keeps the registrations. |
133 | | - |
134 | | -### Authorization helper — `is_staff` bypass for configuration permissions |
135 | | - |
136 | | -`dojo.authorization.authorization.user_has_configuration_permission` now |
137 | | -honors the `is_superuser` / `is_staff` bypass at the top of the function, |
138 | | -matching the rest of the legacy authorization contract (`user_has_permission` |
139 | | -and `user_has_global_permission` already had it). Django's |
140 | | -`user.has_perm(permission)` is consulted as a fallback so explicit grants |
141 | | -on non-staff users keep working. |
142 | | - |
143 | | -This means a non-superuser staff user no longer needs explicit `auth.X` |
144 | | -grants to reach UI/API surfaces gated on configuration permissions |
145 | | -(`/user`, `/group`, `/api/v2/users/`, etc.). |
146 | | - |
147 | | -### `is_staff` is now editable through the UI and API |
148 | | - |
149 | | -* `UserSerializer.Meta.fields` adds `is_staff`. `/api/v2/users/` is already |
150 | | - superuser-only (via `UserHasConfigurationPermissionSuperuser`), so the |
151 | | - field doesn't open a privilege-escalation hole. |
152 | | -* `AddDojoUserForm` and `EditDojoUserForm` add `is_staff`. The widget is |
153 | | - `disabled` for non-superusers; the views `add_user` / `edit_user` reject |
154 | | - the save with an error message if a non-superuser tries to grant or |
155 | | - revoke staff. |
| 10 | +Open Source DefectDojo uses the legacy authorization model: access to a Product is granted by `Product.authorized_users` (with cascade via `Product_Type.authorized_users`), and `is_staff` / `is_superuser` bypass everything. |
| 11 | + |
| 12 | +In 2.58 the classic UI restores the **"Authorized Users"** panel on the Product and Product Type detail pages. The panel reads from and writes to `Product.authorized_users` / `Product_Type.authorized_users` directly, so adding a user actually grants them the access the UI suggests it does. |
| 13 | + |
| 14 | +### New endpoints |
| 15 | + |
| 16 | +- `GET/POST /product/<pid>/authorized_users/add` — list / add users to `Product.authorized_users` |
| 17 | +- `POST /product/<pid>/authorized_users/<user_id>/delete` — remove a user |
| 18 | +- `GET/POST /product/type/<ptid>/authorized_users/add` — same for `Product_Type.authorized_users` |
| 19 | +- `POST /product/type/<ptid>/authorized_users/<user_id>/delete` |
| 20 | + |
| 21 | +Both endpoints are gated so only `is_staff` / `is_superuser` users can add or remove. Non-staff users see the panel but no management actions. |
156 | 22 |
|
157 | 23 | ### Required actions |
158 | 24 |
|
159 | | -* **No data migration required.** Migration `dojo.0267_backfill_authorized_users` |
160 | | - (shipped in 2.57) already populated `authorized_users` from the prior RBAC |
161 | | - tables, so existing access is preserved. |
162 | | -* **If you have a Docker volume mount or in-tree patch overriding any of |
163 | | - the listed templates** (`view_product_details.html`, |
164 | | - `view_product_type.html`, `base.html`, `view_user.html`, `profile.html`, |
165 | | - `add_user.html`): re-apply against the new `{% block %}` structure, or |
166 | | - override the relevant blocks from a parent template. |
167 | | -* **If you call removed v2 API endpoints**: see the table above. |
168 | | -* **If you customized `SystemSettingsForm` / `SystemSettingsSerializer`**: |
169 | | - the three default-group fields are gone; re-add via subclass. |
170 | | -* **If you depend on `auth.X` configuration grants on non-staff users**: |
171 | | - no change. `user.has_perm(permission)` is still consulted. |
| 25 | +- **No data migration required.** Migration `dojo.0267_backfill_authorized_users` (shipped in 2.57) already populated `authorized_users` from the prior RBAC tables, so existing access is preserved. |
| 26 | +- **Audit the migration before you upgrade** with `python manage.py preview_legacy_authorization_migration` (add `--json` for machine-readable output). It is read-only and reports the `authorized_users` pairs that would be created per Product / Product Type (broken down by direct member vs flattened group member), the `is_superuser` / `is_staff` flag flips driven by `Global_Role(Owner)` / `Global_Role(Maintainer | API_Importer)`, and the role-granularity (Reader / Writer / Maintainer per-product) and group-based authorization that the legacy model cannot preserve. Run it on a snapshot of production before the upgrade so you know exactly what will and will not survive. |
| 27 | +- **If you later install Pro on top of an OS deployment**, run `python manage.py reconcile_authorized_users_to_rbac --dry-run` and then re-run without `--dry-run` to apply. It walks `Product.authorized_users` / `Product_Type.authorized_users` and creates the matching `Product_Member` / `Product_Type_Member` rows under a configurable role (`--role Writer` by default), so any `authorized_users` edits you made while running OS-only flow back into Pro RBAC. Idempotent — re-running after a successful apply prints "Already reconciled". |
172 | 28 |
|
173 | 29 | ### Pro customers are not impacted |
174 | 30 |
|
175 | | -DefectDojo Pro retains full RBAC. Pro overrides every new `{% block %}` |
176 | | -hook to re-render the RBAC-driven panels, restores the Groups left-nav |
177 | | -link, re-registers all eight RBAC v2 API endpoints (plus a new |
178 | | -`pro/roles/api` for `/api/v2/roles/`), and runtime-shadows |
179 | | -`user_has_permission` / `user_has_global_permission` / |
180 | | -`user_has_configuration_permission` so configuration permissions follow Pro |
181 | | -RBAC rather than the OS `is_staff` bypass. The Pro UX and API are |
182 | | -unchanged. |
| 31 | +DefectDojo Pro deployments retain full RBAC. The Pro UX is unchanged — same Members/Groups management surface as before. |
183 | 32 |
|
184 | 33 | ## Notification `.tpl` templates relocated |
185 | 34 |
|
|
0 commit comments