From 8db68202569b3d91643a2ad90123b5f6e538bf86 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Thu, 19 Jul 2018 15:03:40 +0300 Subject: [PATCH] Audit Log improvements --- .../server/controller/AlarmController.java | 17 +++++++--- .../server/controller/BaseController.java | 11 +++---- .../controller/EntityRelationController.java | 31 ++++++++++++++++--- .../src/main/resources/thingsboard.yml | 1 + .../server/common/data/audit/ActionType.java | 7 ++++- .../common/data/id/EntityIdFactory.java | 1 + .../server/dao/audit/AuditLogService.java | 19 ++++++------ .../server/dao/audit/AuditLogServiceImpl.java | 14 +++++++-- .../dao/audit/DummyAuditLogServiceImpl.java | 2 +- ui/src/app/common/types.constant.js | 15 +++++++++ ui/src/app/locale/locale.constant-en_US.json | 5 +++ 11 files changed, 93 insertions(+), 30 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java index 28cc2fdf09..51ef5668bd 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java @@ -26,6 +26,7 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmId; import org.thingsboard.server.common.data.alarm.AlarmInfo; @@ -33,6 +34,7 @@ import org.thingsboard.server.common.data.alarm.AlarmQuery; import org.thingsboard.server.common.data.alarm.AlarmSearchStatus; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.alarm.AlarmStatus; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; @@ -53,7 +55,6 @@ public class AlarmController extends BaseController { checkParameter(ALARM_ID, strAlarmId); try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); - return checkAlarmId(alarmId); } catch (Exception e) { throw handleException(e); @@ -79,8 +80,14 @@ public class AlarmController extends BaseController { public Alarm saveAlarm(@RequestBody Alarm alarm) throws ThingsboardException { try { alarm.setTenantId(getCurrentUser().getTenantId()); - return checkNotNull(alarmService.createOrUpdateAlarm(alarm)); + Alarm savedAlarm = checkNotNull(alarmService.createOrUpdateAlarm(alarm)); + logEntityAction(savedAlarm.getId(), savedAlarm, + getCurrentUser().getCustomerId(), + savedAlarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, null); + return savedAlarm; } catch (Exception e) { + logEntityAction(emptyId(EntityType.ASSET), alarm, + null, alarm.getId() == null ? ActionType.ADDED : ActionType.UPDATED, e); throw handleException(e); } } @@ -92,8 +99,9 @@ public class AlarmController extends BaseController { checkParameter(ALARM_ID, strAlarmId); try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); - checkAlarmId(alarmId); + Alarm alarm = checkAlarmId(alarmId); alarmService.ackAlarm(alarmId, System.currentTimeMillis()).get(); + logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_ACK, null); } catch (Exception e) { throw handleException(e); } @@ -106,8 +114,9 @@ public class AlarmController extends BaseController { checkParameter(ALARM_ID, strAlarmId); try { AlarmId alarmId = new AlarmId(toUUID(strAlarmId)); - checkAlarmId(alarmId); + Alarm alarm = checkAlarmId(alarmId); alarmService.clearAlarm(alarmId, null, System.currentTimeMillis()).get(); + logEntityAction(alarmId, alarm, getCurrentUser().getCustomerId(), ActionType.ALARM_CLEAR, null); } catch (Exception e) { throw handleException(e); } diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index f04422898c..de73fe0796 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -529,18 +529,16 @@ public abstract class BaseController { return baseUrl; } - protected I emptyId(EntityType entityType) { + protected I emptyId(EntityType entityType) { return (I)EntityIdFactory.getByTypeAndUuid(entityType, ModelConstants.NULL_UUID); } - protected & HasName, - I extends UUIDBased & EntityId> void logEntityAction(I entityId, E entity, CustomerId customerId, + protected void logEntityAction(I entityId, E entity, CustomerId customerId, ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException { logEntityAction(getCurrentUser(), entityId, entity, customerId, actionType, e, additionalInfo); } - protected & HasName, - I extends UUIDBased & EntityId> void logEntityAction(User user, I entityId, E entity, CustomerId customerId, + protected void logEntityAction(User user, I entityId, E entity, CustomerId customerId, ActionType actionType, Exception e, Object... additionalInfo) throws ThingsboardException { if (customerId == null || customerId.isNullUid()) { customerId = user.getCustomerId(); @@ -556,8 +554,7 @@ public abstract class BaseController { return error != null ? (Exception.class.isInstance(error) ? (Exception) error : new Exception(error)) : null; } - private & HasName, - I extends UUIDBased & EntityId> void pushEntityActionToRuleEngine(I entityId, E entity, User user, CustomerId customerId, + private void pushEntityActionToRuleEngine(I entityId, E entity, User user, CustomerId customerId, ActionType actionType, Object... additionalInfo) { String msgType = null; switch (actionType) { diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java index 844dbd35a9..70dd8a643e 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java @@ -24,10 +24,13 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.thingsboard.server.common.data.alarm.Alarm; +import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.relation.EntityRelationInfo; import org.thingsboard.server.common.data.relation.EntityRelationsQuery; @@ -58,7 +61,15 @@ public class EntityRelationController extends BaseController { relation.setTypeGroup(RelationTypeGroup.COMMON); } relationService.saveRelation(relation); + logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), + ActionType.RELATION_ADD_OR_UPDATE, null, relation); + logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(), + ActionType.RELATION_ADD_OR_UPDATE, null, relation); } catch (Exception e) { + logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), + ActionType.RELATION_ADD_OR_UPDATE, e, relation); + logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(), + ActionType.RELATION_ADD_OR_UPDATE, e, relation); throw handleException(e); } } @@ -81,12 +92,21 @@ public class EntityRelationController extends BaseController { checkEntityId(fromId); checkEntityId(toId); RelationTypeGroup relationTypeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON); + EntityRelation relation = new EntityRelation(fromId, toId, strRelationType, relationTypeGroup); try { Boolean found = relationService.deleteRelation(fromId, toId, strRelationType, relationTypeGroup); if (!found) { throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND); } + logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), + ActionType.RELATION_DELETED, null, relation); + logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(), + ActionType.RELATION_DELETED, null, relation); } catch (Exception e) { + logEntityAction(relation.getFrom(), null, getCurrentUser().getCustomerId(), + ActionType.RELATION_DELETED, e, relation); + logEntityAction(relation.getTo(), null, getCurrentUser().getCustomerId(), + ActionType.RELATION_DELETED, e, relation); throw handleException(e); } } @@ -102,7 +122,9 @@ public class EntityRelationController extends BaseController { checkEntityId(entityId); try { relationService.deleteEntityRelations(entityId); + logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, null); } catch (Exception e) { + logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, e); throw handleException(e); } } @@ -210,8 +232,8 @@ public class EntityRelationController extends BaseController { @RequestMapping(value = "/relations/info", method = RequestMethod.GET, params = {TO_ID, TO_TYPE}) @ResponseBody public List findInfoByTo(@RequestParam(TO_ID) String strToId, - @RequestParam(TO_TYPE) String strToType, - @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { + @RequestParam(TO_TYPE) String strToType, + @RequestParam(value = "relationTypeGroup", required = false) String strRelationTypeGroup) throws ThingsboardException { checkParameter(TO_ID, strToId); checkParameter(TO_TYPE, strToType); EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId); @@ -276,10 +298,11 @@ public class EntityRelationController extends BaseController { private RelationTypeGroup parseRelationTypeGroup(String strRelationTypeGroup, RelationTypeGroup defaultValue) { RelationTypeGroup result = defaultValue; - if (strRelationTypeGroup != null && strRelationTypeGroup.trim().length()>0) { + if (strRelationTypeGroup != null && strRelationTypeGroup.trim().length() > 0) { try { result = RelationTypeGroup.valueOf(strRelationTypeGroup); - } catch (IllegalArgumentException e) { } + } catch (IllegalArgumentException e) { + } } return result; } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 2a2728dbb4..9f6192b51d 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -385,6 +385,7 @@ audit_log: "customer": "${AUDIT_LOG_MASK_CUSTOMER:W}" "user": "${AUDIT_LOG_MASK_USER:W}" "rule_chain": "${AUDIT_LOG_MASK_RULE_CHAIN:W}" + "alarm": "${AUDIT_LOG_MASK_ALARM:W}" sink: # Type of external sink. possible options: none, elasticsearch type: "${AUDIT_LOG_SINK_TYPE:none}" diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java b/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java index ea442f0c53..c37d4607c3 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/audit/ActionType.java @@ -31,7 +31,12 @@ public enum ActionType { ACTIVATED(false), // log string id SUSPENDED(false), // log string id CREDENTIALS_READ(true), // log device id - ATTRIBUTES_READ(true); // log attributes + ATTRIBUTES_READ(true), // log attributes + RELATION_ADD_OR_UPDATE (false), + RELATION_DELETED (false), + RELATIONS_DELETED (false), + ALARM_ACK (false), + ALARM_CLEAR (false); private final boolean isRead; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java index 0ecc7c639f..ed4cf2f784 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/EntityIdFactory.java @@ -60,4 +60,5 @@ public class EntityIdFactory { } throw new IllegalArgumentException("EntityType " + type + " is not supported!"); } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogService.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogService.java index d2e6f056e0..b9db33810a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogService.java @@ -40,15 +40,14 @@ public interface AuditLogService { TimePageData findAuditLogsByTenantId(TenantId tenantId, TimePageLink pageLink); - & HasName, - I extends UUIDBased & EntityId> ListenableFuture> logEntityAction( - TenantId tenantId, - CustomerId customerId, - UserId userId, - String userName, - I entityId, - E entity, - ActionType actionType, - Exception e, Object... additionalInfo); + ListenableFuture> logEntityAction( + TenantId tenantId, + CustomerId customerId, + UserId userId, + String userName, + I entityId, + E entity, + ActionType actionType, + Exception e, Object... additionalInfo); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java index a30c1b453b..ecb2bd5a27 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/AuditLogServiceImpl.java @@ -43,6 +43,7 @@ import org.thingsboard.server.common.data.id.UserId; import org.thingsboard.server.common.data.kv.AttributeKvEntry; import org.thingsboard.server.common.data.page.TimePageData; import org.thingsboard.server.common.data.page.TimePageLink; +import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.rule.RuleChainMetaData; import org.thingsboard.server.common.data.security.DeviceCredentials; import org.thingsboard.server.dao.audit.sink.AuditLogSink; @@ -115,7 +116,7 @@ public class AuditLogServiceImpl implements AuditLogService { } @Override - public & HasName, I extends UUIDBased & EntityId> ListenableFuture> + public ListenableFuture> logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, ActionType actionType, Exception e, Object... additionalInfo) { if (canLog(entityId.getEntityType(), actionType)) { @@ -156,14 +157,16 @@ public class AuditLogServiceImpl implements AuditLogService { } } - private & HasName, I extends UUIDBased & EntityId> JsonNode constructActionData(I entityId, - E entity, + private JsonNode constructActionData(I entityId, E entity, ActionType actionType, Object... additionalInfo) { ObjectNode actionData = objectMapper.createObjectNode(); switch(actionType) { case ADDED: case UPDATED: + case ALARM_ACK: + case ALARM_CLEAR: + case RELATIONS_DELETED: if (entity != null) { ObjectNode entityNode = objectMapper.valueToTree(entity); if (entityId.getEntityType() == EntityType.DASHBOARD) { @@ -240,6 +243,11 @@ public class AuditLogServiceImpl implements AuditLogService { actionData.put("unassignedCustomerId", strCustomerId); actionData.put("unassignedCustomerName", strCustomerName); break; + case RELATION_ADD_OR_UPDATE: + case RELATION_DELETED: + EntityRelation relation = extractParameter(EntityRelation.class, 0, additionalInfo); + actionData.set("relation", objectMapper.valueToTree(relation)); + break; } return actionData; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java index b14d6b196d..6f9ea36222 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/audit/DummyAuditLogServiceImpl.java @@ -57,7 +57,7 @@ public class DummyAuditLogServiceImpl implements AuditLogService { } @Override - public & HasName, I extends UUIDBased & EntityId> ListenableFuture> logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, ActionType actionType, Exception e, Object... additionalInfo) { + public ListenableFuture> logEntityAction(TenantId tenantId, CustomerId customerId, UserId userId, String userName, I entityId, E entity, ActionType actionType, Exception e, Object... additionalInfo) { return null; } diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js index 3ba99fa5ce..1e34577119 100644 --- a/ui/src/app/common/types.constant.js +++ b/ui/src/app/common/types.constant.js @@ -195,6 +195,21 @@ export default angular.module('thingsboard.types', []) }, "ATTRIBUTES_READ": { name: "audit-log.type-attributes-read" + }, + "RELATION_ADD_OR_UPDATE": { + name: "audit-log.type-relation-add-or-update" + }, + "RELATION_DELETED": { + name: "audit-log.type-relation-delete" + }, + "RELATIONS_DELETED": { + name: "audit-log.type-relations-delete" + }, + "ALARM_ACK": { + name: "audit-log.type-alarm-ack" + }, + "ALARM_CLEAR": { + name: "audit-log.type-alarm-clear" } }, auditLogActionStatus: { diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index dcf428542c..c664259c8a 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -288,6 +288,11 @@ "type-suspended": "Suspended", "type-credentials-read": "Credentials read", "type-attributes-read": "Attributes read", + "type-relation-add-or-update": "Relation updated", + "type-relation-delete": "Relation deleted", + "type-relations-delete": "All relation deleted", + "type-alarm-ack": "Acknowledged", + "type-alarm-clear": "Cleared", "status-success": "Success", "status-failure": "Failure", "audit-log-details": "Audit log details",