Code review fixes
This commit is contained in:
parent
fad04b0dd0
commit
92fdbbf89c
@ -15,9 +15,12 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.controller;
|
package org.thingsboard.server.controller;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.security.core.Authentication;
|
import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
@ -27,6 +30,8 @@ import org.thingsboard.server.common.data.alarm.Alarm;
|
|||||||
import org.thingsboard.server.common.data.alarm.AlarmId;
|
import org.thingsboard.server.common.data.alarm.AlarmId;
|
||||||
import org.thingsboard.server.common.data.alarm.AlarmInfo;
|
import org.thingsboard.server.common.data.alarm.AlarmInfo;
|
||||||
import org.thingsboard.server.common.data.asset.Asset;
|
import org.thingsboard.server.common.data.asset.Asset;
|
||||||
|
import org.thingsboard.server.common.data.audit.ActionStatus;
|
||||||
|
import org.thingsboard.server.common.data.audit.ActionType;
|
||||||
import org.thingsboard.server.common.data.id.*;
|
import org.thingsboard.server.common.data.id.*;
|
||||||
import org.thingsboard.server.common.data.page.TextPageLink;
|
import org.thingsboard.server.common.data.page.TextPageLink;
|
||||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||||
@ -73,6 +78,10 @@ public abstract class BaseController {
|
|||||||
|
|
||||||
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
|
||||||
public static final String YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION = "You don't have permission to perform this operation!";
|
public static final String YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION = "You don't have permission to perform this operation!";
|
||||||
|
|
||||||
|
@Value("${audit_log.exceptions.enabled}")
|
||||||
|
private boolean auditLogExceptionsEnabled;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ThingsboardErrorResponseHandler errorResponseHandler;
|
private ThingsboardErrorResponseHandler errorResponseHandler;
|
||||||
|
|
||||||
@ -131,6 +140,11 @@ public abstract class BaseController {
|
|||||||
return handleException(exception, true);
|
return handleException(exception, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThingsboardException handleException(Exception exception, ActionType actionType, String actionData) {
|
||||||
|
logExceptionToAuditLog(exception, actionType, actionData);
|
||||||
|
return handleException(exception, true);
|
||||||
|
}
|
||||||
|
|
||||||
private ThingsboardException handleException(Exception exception, boolean logException) {
|
private ThingsboardException handleException(Exception exception, boolean logException) {
|
||||||
if (logException) {
|
if (logException) {
|
||||||
log.error("Error [{}]", exception.getMessage());
|
log.error("Error [{}]", exception.getMessage());
|
||||||
@ -153,6 +167,36 @@ public abstract class BaseController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void logExceptionToAuditLog(Exception exception, ActionType actionType, String actionData) {
|
||||||
|
try {
|
||||||
|
if (auditLogExceptionsEnabled) {
|
||||||
|
SecurityUser currentUser = getCurrentUser();
|
||||||
|
EntityId entityId;
|
||||||
|
CustomerId customerId;
|
||||||
|
if (!currentUser.getCustomerId().getId().equals(ModelConstants.NULL_UUID)) {
|
||||||
|
entityId = currentUser.getCustomerId();
|
||||||
|
customerId = currentUser.getCustomerId();
|
||||||
|
} else {
|
||||||
|
entityId = currentUser.getTenantId();
|
||||||
|
customerId = new CustomerId(ModelConstants.NULL_UUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonNode actionDataNode = new ObjectMapper().createObjectNode().put("actionData", actionData);
|
||||||
|
|
||||||
|
auditLogService.logEntityAction(currentUser,
|
||||||
|
entityId,
|
||||||
|
null,
|
||||||
|
customerId,
|
||||||
|
actionType,
|
||||||
|
actionDataNode,
|
||||||
|
ActionStatus.FAILURE,
|
||||||
|
exception.getMessage());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception happend during saving to audit log", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
<T> T checkNotNull(T reference) throws ThingsboardException {
|
<T> T checkNotNull(T reference) throws ThingsboardException {
|
||||||
if (reference == null) {
|
if (reference == null) {
|
||||||
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
|
throw new ThingsboardException("Requested item wasn't found!", ThingsboardErrorCode.ITEM_NOT_FOUND);
|
||||||
@ -545,4 +589,24 @@ public abstract class BaseController {
|
|||||||
serverPort);
|
serverPort);
|
||||||
return baseUrl;
|
return baseUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void logEntityDeleted(EntityId entityId, String entityName, CustomerId customerId) throws ThingsboardException {
|
||||||
|
logEntitySuccess(entityId, entityName, customerId, ActionType.DELETED);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void logEntityAddedOrUpdated(EntityId entityId, String entityName, CustomerId customerId, boolean isAddAction) throws ThingsboardException {
|
||||||
|
logEntitySuccess(entityId, entityName, customerId, isAddAction ? ActionType.ADDED : ActionType.UPDATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void logEntitySuccess(EntityId entityId, String entityName, CustomerId customerId, ActionType actionType) throws ThingsboardException {
|
||||||
|
auditLogService.logEntityAction(
|
||||||
|
getCurrentUser(),
|
||||||
|
entityId,
|
||||||
|
entityName,
|
||||||
|
customerId,
|
||||||
|
actionType,
|
||||||
|
null,
|
||||||
|
ActionStatus.SUCCESS,
|
||||||
|
null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -85,20 +85,11 @@ public class DeviceController extends BaseController {
|
|||||||
savedDevice.getName(),
|
savedDevice.getName(),
|
||||||
savedDevice.getType());
|
savedDevice.getType());
|
||||||
|
|
||||||
auditLogService.logEntityAction(
|
logEntityAddedOrUpdated(savedDevice.getId(), savedDevice.getName(), savedDevice.getCustomerId(), device.getId() == null);
|
||||||
getCurrentUser(),
|
|
||||||
savedDevice.getId(),
|
|
||||||
savedDevice.getName(),
|
|
||||||
savedDevice.getCustomerId(),
|
|
||||||
device.getId() == null ? ActionType.ADDED : ActionType.UPDATED,
|
|
||||||
null,
|
|
||||||
ActionStatus.SUCCESS,
|
|
||||||
null);
|
|
||||||
|
|
||||||
|
|
||||||
return savedDevice;
|
return savedDevice;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw handleException(e);
|
throw handleException(e, device.getId() == null ? ActionType.ADDED : ActionType.UPDATED, "addDevice(" + device + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,17 +102,9 @@ public class DeviceController extends BaseController {
|
|||||||
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
|
DeviceId deviceId = new DeviceId(toUUID(strDeviceId));
|
||||||
Device device = checkDeviceId(deviceId);
|
Device device = checkDeviceId(deviceId);
|
||||||
deviceService.deleteDevice(deviceId);
|
deviceService.deleteDevice(deviceId);
|
||||||
auditLogService.logEntityAction(
|
logEntityDeleted(device.getId(), device.getName(), device.getCustomerId());
|
||||||
getCurrentUser(),
|
|
||||||
device.getId(),
|
|
||||||
device.getName(),
|
|
||||||
device.getCustomerId(),
|
|
||||||
ActionType.DELETED,
|
|
||||||
null,
|
|
||||||
ActionStatus.SUCCESS,
|
|
||||||
null);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw handleException(e);
|
throw handleException(e, ActionType.DELETED, "deleteDevice(" + strDeviceId + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,18 +183,10 @@ public class DeviceController extends BaseController {
|
|||||||
Device device = checkDeviceId(deviceCredentials.getDeviceId());
|
Device device = checkDeviceId(deviceCredentials.getDeviceId());
|
||||||
DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(deviceCredentials));
|
DeviceCredentials result = checkNotNull(deviceCredentialsService.updateDeviceCredentials(deviceCredentials));
|
||||||
actorService.onCredentialsUpdate(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId());
|
actorService.onCredentialsUpdate(getCurrentUser().getTenantId(), deviceCredentials.getDeviceId());
|
||||||
auditLogService.logEntityAction(
|
logEntitySuccess(device.getId(), device.getName(), device.getCustomerId(), ActionType.CREDENTIALS_UPDATED);
|
||||||
getCurrentUser(),
|
|
||||||
device.getId(),
|
|
||||||
device.getName(),
|
|
||||||
device.getCustomerId(),
|
|
||||||
ActionType.CREDENTIALS_UPDATED,
|
|
||||||
null,
|
|
||||||
ActionStatus.SUCCESS,
|
|
||||||
null);
|
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw handleException(e);
|
throw handleException(e, ActionType.CREDENTIALS_UPDATED, "saveDeviceCredentials(" + deviceCredentials + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -286,4 +286,11 @@ spring:
|
|||||||
# Audit log parameters
|
# Audit log parameters
|
||||||
audit_log:
|
audit_log:
|
||||||
# Enable/disable audit log functionality.
|
# Enable/disable audit log functionality.
|
||||||
enabled: "${AUDIT_LOG_ENABLED:true}"
|
enabled: "${AUDIT_LOG_ENABLED:true}"
|
||||||
|
# Specify partitioning size for audit log by tenant id storage. Example MINUTES, HOURS, DAYS, MONTHS
|
||||||
|
by_tenant_partitioning: "${AUDIT_LOG_BY_TENANT_PARTITIONING:MONTHS}"
|
||||||
|
# Number of days as history period if startTime and endTime are not specified
|
||||||
|
default_query_period: "${AUDIT_LOG_DEFAULT_QUERY_PERIOD:30}"
|
||||||
|
exceptions:
|
||||||
|
# Enable/disable audit log functionality for exceptions.
|
||||||
|
enabled: "${AUDIT_LOG_EXCEPTIONS_ENABLED:true}"
|
||||||
@ -81,10 +81,13 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
|
|||||||
|
|
||||||
protected ExecutorService readResultsProcessingExecutor;
|
protected ExecutorService readResultsProcessingExecutor;
|
||||||
|
|
||||||
@Value("${cassandra.query.ts_key_value_partitioning}")
|
@Value("${audit_log.by_tenant_partitioning}")
|
||||||
private String partitioning;
|
private String partitioning;
|
||||||
private TsPartitionDate tsFormat;
|
private TsPartitionDate tsFormat;
|
||||||
|
|
||||||
|
@Value("${audit_log.default_query_period}")
|
||||||
|
private Integer defaultQueryPeriodInDays;
|
||||||
|
|
||||||
private PreparedStatement partitionInsertStmt;
|
private PreparedStatement partitionInsertStmt;
|
||||||
private PreparedStatement saveByTenantStmt;
|
private PreparedStatement saveByTenantStmt;
|
||||||
private PreparedStatement saveByTenantIdAndUserIdStmt;
|
private PreparedStatement saveByTenantIdAndUserIdStmt;
|
||||||
@ -304,7 +307,7 @@ public class CassandraAuditLogDao extends CassandraAbstractSearchTimeDao<AuditLo
|
|||||||
if (pageLink.getStartTime() != null && pageLink.getStartTime() != 0) {
|
if (pageLink.getStartTime() != null && pageLink.getStartTime() != 0) {
|
||||||
minPartition = toPartitionTs(pageLink.getStartTime());
|
minPartition = toPartitionTs(pageLink.getStartTime());
|
||||||
} else {
|
} else {
|
||||||
minPartition = toPartitionTs(LocalDate.now().minusMonths(1).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli());
|
minPartition = toPartitionTs(LocalDate.now().minusDays(defaultQueryPeriodInDays).atStartOfDay().toInstant(ZoneOffset.UTC).toEpochMilli());
|
||||||
}
|
}
|
||||||
|
|
||||||
long maxPartition;
|
long maxPartition;
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
package org.thingsboard.server.dao.audit;
|
package org.thingsboard.server.dao.audit;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||||
import org.thingsboard.server.common.data.User;
|
import org.thingsboard.server.common.data.User;
|
||||||
@ -29,6 +30,7 @@ import org.thingsboard.server.common.data.id.UserId;
|
|||||||
import org.thingsboard.server.common.data.page.TimePageData;
|
import org.thingsboard.server.common.data.page.TimePageData;
|
||||||
import org.thingsboard.server.common.data.page.TimePageLink;
|
import org.thingsboard.server.common.data.page.TimePageLink;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ConditionalOnProperty(prefix = "audit_log", value = "enabled", havingValue = "false")
|
@ConditionalOnProperty(prefix = "audit_log", value = "enabled", havingValue = "false")
|
||||||
@ -36,26 +38,26 @@ public class DummyAuditLogServiceImpl implements AuditLogService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimePageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink) {
|
public TimePageData<AuditLog> findAuditLogsByTenantIdAndCustomerId(TenantId tenantId, CustomerId customerId, TimePageLink pageLink) {
|
||||||
return null;
|
return new TimePageData<>(null, pageLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimePageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, TimePageLink pageLink) {
|
public TimePageData<AuditLog> findAuditLogsByTenantIdAndUserId(TenantId tenantId, UserId userId, TimePageLink pageLink) {
|
||||||
return null;
|
return new TimePageData<>(null, pageLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink) {
|
public TimePageData<AuditLog> findAuditLogsByTenantIdAndEntityId(TenantId tenantId, EntityId entityId, TimePageLink pageLink) {
|
||||||
return null;
|
return new TimePageData<>(null, pageLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TimePageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, TimePageLink pageLink) {
|
public TimePageData<AuditLog> findAuditLogsByTenantId(TenantId tenantId, TimePageLink pageLink) {
|
||||||
return null;
|
return new TimePageData<>(null, pageLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListenableFuture<List<Void>> logEntityAction(User user, EntityId entityId, String entityName, CustomerId customerId, ActionType actionType, JsonNode actionData, ActionStatus actionStatus, String actionFailureDetails) {
|
public ListenableFuture<List<Void>> logEntityAction(User user, EntityId entityId, String entityName, CustomerId customerId, ActionType actionType, JsonNode actionData, ActionStatus actionStatus, String actionFailureDetails) {
|
||||||
return null;
|
return Futures.immediateFuture(Collections.emptyList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,9 @@ zk.zk_dir=/thingsboard
|
|||||||
updates.enabled=false
|
updates.enabled=false
|
||||||
|
|
||||||
audit_log.enabled=true
|
audit_log.enabled=true
|
||||||
|
audit_log.exceptions.enabled=false
|
||||||
|
audit_log.by_tenant_partitioning=MONTHS
|
||||||
|
audit_log.default_query_period=30
|
||||||
|
|
||||||
caching.specs.relations.timeToLiveInMinutes=1440
|
caching.specs.relations.timeToLiveInMinutes=1440
|
||||||
caching.specs.relations.maxSize=100000
|
caching.specs.relations.maxSize=100000
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user