@@ -80,9 +80,19 @@ Future<Response> _handleGet(
80
80
User authenticatedUser,
81
81
String requestId,
82
82
) async {
83
+ // Apply access control based on ownership type for GET requests
84
+ if (modelConfig.ownership == ModelOwnership .adminOwned &&
85
+ ! authenticatedUser.isAdmin) {
86
+ throw const ForbiddenException (
87
+ 'You do not have permission to read this resource.' ,
88
+ );
89
+ }
90
+
83
91
dynamic item;
84
92
85
93
String ? userIdForRepoCall;
94
+ // For userOwned models, pass the authenticated user's ID to the repository
95
+ // for filtering. For adminOwned/adminOwnedReadAllowed, pass null.
86
96
if (modelConfig.ownership == ModelOwnership .userOwned) {
87
97
userIdForRepoCall = authenticatedUser.id;
88
98
} else {
@@ -188,14 +198,29 @@ Future<Response> _handlePut(
188
198
);
189
199
}
190
200
201
+ // Apply access control based on ownership type for PUT requests
202
+ if ((modelConfig.ownership == ModelOwnership .adminOwned ||
203
+ modelConfig.ownership == ModelOwnership .adminOwnedReadAllowed) &&
204
+ ! authenticatedUser.isAdmin) {
205
+ throw const ForbiddenException (
206
+ 'Only administrators can update this resource.' ,
207
+ );
208
+ }
209
+ if (modelConfig.ownership == ModelOwnership .userOwned &&
210
+ ! authenticatedUser.isAdmin) {
211
+ // For userOwned, non-admins must be the owner.
212
+ // The repository will enforce this check when userIdForRepoCall is passed.
213
+ }
214
+
191
215
dynamic updatedItem;
192
216
193
217
String ? userIdForRepoCall;
218
+ // For userOwned models, pass the authenticated user's ID to the repository
219
+ // for ownership enforcement. For adminOwned/adminOwnedReadAllowed, pass null
220
+ // (repository handles admin updates).
194
221
if (modelConfig.ownership == ModelOwnership .userOwned) {
195
222
userIdForRepoCall = authenticatedUser.id;
196
223
} else {
197
- // TODO(fulleni): For global models, update might imply admin rights.
198
- // For now, pass null, consider adding an admin user check.
199
224
userIdForRepoCall = null ;
200
225
}
201
226
@@ -323,12 +348,27 @@ Future<Response> _handleDelete(
323
348
User authenticatedUser,
324
349
String requestId,
325
350
) async {
351
+ // Apply access control based on ownership type for DELETE requests
352
+ if ((modelConfig.ownership == ModelOwnership .adminOwned ||
353
+ modelConfig.ownership == ModelOwnership .adminOwnedReadAllowed) &&
354
+ ! authenticatedUser.isAdmin) {
355
+ throw const ForbiddenException (
356
+ 'Only administrators can delete this resource.' ,
357
+ );
358
+ }
359
+ if (modelConfig.ownership == ModelOwnership .userOwned &&
360
+ ! authenticatedUser.isAdmin) {
361
+ // For userOwned, non-admins must be the owner.
362
+ // The repository will enforce this check when userIdForRepoCall is passed.
363
+ }
364
+
326
365
String ? userIdForRepoCall;
366
+ // For userOwned models, pass the authenticated user's ID to the repository
367
+ // for ownership enforcement. For adminOwned/adminOwnedReadAllowed, pass null
368
+ // (repository handles admin deletions).
327
369
if (modelConfig.ownership == ModelOwnership .userOwned) {
328
370
userIdForRepoCall = authenticatedUser.id;
329
371
} else {
330
- // TODO(fulleni): For global models, update might imply admin rights.
331
- // For now, pass null, consider adding an admin user check.
332
372
userIdForRepoCall = null ;
333
373
}
334
374
0 commit comments