@@ -80,9 +80,19 @@ Future<Response> _handleGet(
8080 User authenticatedUser,
8181 String requestId,
8282) 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+
8391 dynamic item;
8492
8593 String ? userIdForRepoCall;
94+ // For userOwned models, pass the authenticated user's ID to the repository
95+ // for filtering. For adminOwned/adminOwnedReadAllowed, pass null.
8696 if (modelConfig.ownership == ModelOwnership .userOwned) {
8797 userIdForRepoCall = authenticatedUser.id;
8898 } else {
@@ -188,14 +198,29 @@ Future<Response> _handlePut(
188198 );
189199 }
190200
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+
191215 dynamic updatedItem;
192216
193217 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).
194221 if (modelConfig.ownership == ModelOwnership .userOwned) {
195222 userIdForRepoCall = authenticatedUser.id;
196223 } else {
197- // TODO(fulleni): For global models, update might imply admin rights.
198- // For now, pass null, consider adding an admin user check.
199224 userIdForRepoCall = null ;
200225 }
201226
@@ -323,12 +348,27 @@ Future<Response> _handleDelete(
323348 User authenticatedUser,
324349 String requestId,
325350) 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+
326365 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).
327369 if (modelConfig.ownership == ModelOwnership .userOwned) {
328370 userIdForRepoCall = authenticatedUser.id;
329371 } else {
330- // TODO(fulleni): For global models, update might imply admin rights.
331- // For now, pass null, consider adding an admin user check.
332372 userIdForRepoCall = null ;
333373 }
334374
0 commit comments