From ae2fdf85f2651792ce2db09e7a2066ecefb59629 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 1 Jun 2026 12:28:21 +0300 Subject: [PATCH] fixed alarm comment update flow validation --- .../server/controller/AlarmCommentController.java | 12 ++++++++++-- .../controller/AlarmCommentControllerTest.java | 5 ++++- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java index 90a20880f6..c9d2b6fef7 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmCommentController.java @@ -78,7 +78,10 @@ public class AlarmCommentController extends BaseController { checkParameter(ALARM_ID, strAlarmId); AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); Alarm alarm = checkAlarmInfoId(alarmId, Operation.WRITE); - checkUserCommentOwnership(alarmComment, Operation.WRITE); + if (alarmComment.getId() != null) { + AlarmComment existingAlarmComment = checkAlarmCommentId(alarmComment.getId(), alarmId); + checkUserCommentOwnership(existingAlarmComment, Operation.WRITE); + } alarmComment.setAlarmId(alarmId); alarmComment.setType(AlarmCommentType.OTHER); return tbAlarmCommentService.saveAlarmComment(alarm, alarmComment, getCurrentUser()); @@ -125,7 +128,12 @@ public class AlarmCommentController extends BaseController { private void checkUserCommentOwnership(AlarmComment alarmComment, Operation operation) throws ThingsboardException { if (alarmComment.getUserId() != null && !alarmComment.getUserId().equals(getCurrentUser().getId())) { - throw new ThingsboardException("User is not allowed to " + operation.name().toLowerCase() + " other user's comment", + String action = switch (operation) { + case WRITE -> "edit"; + case DELETE -> "delete"; + default -> "perform this operation with"; + }; + throw new ThingsboardException("User is not allowed to " + action + " other user's comment", ThingsboardErrorCode.PERMISSION_DENIED); } } diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmCommentControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmCommentControllerTest.java index f2599d3adf..e8e9412dc6 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmCommentControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmCommentControllerTest.java @@ -172,10 +172,13 @@ public class AlarmCommentControllerTest extends AbstractControllerTest { JsonNode newComment = JacksonUtil.newObjectNode().set("text", new TextNode("Tenant rewrite attempt")); alarmComment.setComment(newComment); + // Simulate the real attack: the attacker controls the request body and would omit (or spoof) + // the userId. Ownership must be enforced against the persisted comment, not the body. + alarmComment.setUserId(null); doPost("/api/alarm/" + alarm.getId() + "/comment", alarmComment) .andExpect(status().isForbidden()) - .andExpect(statusReason(containsString("User is not allowed to write other user's comment"))); + .andExpect(statusReason(containsString("User is not allowed to edit other user's comment"))); testNotifyEntityNever(alarm.getId(), alarmComment); }