thingsboard-developers

Changes

Details

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 16ba5a5..b43ccf4 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AlarmController.java
@@ -150,7 +150,7 @@ public class AlarmController extends BaseController {
             throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " +
                     "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
         }
-        checkEntityId(entityId);
+        checkEntityId(entityId, Operation.READ);
         try {
             TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
             return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get());
@@ -177,7 +177,7 @@ public class AlarmController extends BaseController {
             throw new ThingsboardException("Invalid alarms search query: Both parameters 'searchStatus' " +
                     "and 'status' can't be specified at the same time!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
         }
-        checkEntityId(entityId);
+        checkEntityId(entityId, Operation.READ);
         try {
             return alarmService.findHighestAlarmSeverity(getCurrentUser().getTenantId(), entityId, alarmSearchStatus, alarmStatus);
         } catch (Exception e) {
diff --git a/application/src/main/java/org/thingsboard/server/controller/AssetController.java b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
index 55e087b..bd0ca65 100644
--- a/application/src/main/java/org/thingsboard/server/controller/AssetController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/AssetController.java
@@ -300,12 +300,11 @@ public class AssetController extends BaseController {
         checkNotNull(query);
         checkNotNull(query.getParameters());
         checkNotNull(query.getAssetTypes());
-        checkEntityId(query.getParameters().getEntityId());
+        checkEntityId(query.getParameters().getEntityId(), Operation.READ);
         try {
             List<Asset> assets = checkNotNull(assetService.findAssetsByQuery(getTenantId(), query).get());
             assets = assets.stream().filter(asset -> {
                 try {
-                    //checkAsset(asset);
                     accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, Operation.READ, asset.getId(), asset);
                     return true;
                 } catch (ThingsboardException 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 1888cff..702fdd9 100644
--- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java
@@ -44,6 +44,7 @@ import org.thingsboard.server.common.data.page.TimePageLink;
 import org.thingsboard.server.common.data.plugin.ComponentDescriptor;
 import org.thingsboard.server.common.data.plugin.ComponentType;
 import org.thingsboard.server.common.data.rule.RuleChain;
+import org.thingsboard.server.common.data.rule.RuleNode;
 import org.thingsboard.server.common.data.security.Authority;
 import org.thingsboard.server.common.data.widget.WidgetType;
 import org.thingsboard.server.common.data.widget.WidgetsBundle;
@@ -258,14 +259,9 @@ public abstract class BaseController {
         }
     }
 
-    void checkTenantId(TenantId tenantId) throws ThingsboardException {
+    void checkTenantId(TenantId tenantId, Operation operation) throws ThingsboardException {
         validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
-        SecurityUser authUser = getCurrentUser();
-        if (authUser.getAuthority() != Authority.SYS_ADMIN &&
-                (authUser.getTenantId() == null || !authUser.getTenantId().equals(tenantId))) {
-            throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
-                    ThingsboardErrorCode.PERMISSION_DENIED);
-        }
+        accessControlService.checkPermission(getCurrentUser(), tenantId, Resource.TENANT, operation, tenantId);
     }
 
     protected TenantId getTenantId() throws ThingsboardException {
@@ -274,19 +270,11 @@ public abstract class BaseController {
 
     Customer checkCustomerId(CustomerId customerId, Operation operation) throws ThingsboardException {
         try {
-            /*SecurityUser authUser = getCurrentUser();
-            if (authUser.getAuthority() == Authority.SYS_ADMIN ||
-                    (authUser.getAuthority() != Authority.TENANT_ADMIN &&
-                            (authUser.getCustomerId() == null || !authUser.getCustomerId().equals(customerId)))) {
-                throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
-                        ThingsboardErrorCode.PERMISSION_DENIED);
-            }*/
             accessControlService.checkPermission(getCurrentUser(), getCurrentUser().getTenantId(), Resource.CUSTOMER, operation, customerId);
 
             if (customerId != null && !customerId.isNullUid()) {
                 Customer customer = customerService.findCustomerById(getTenantId(), customerId);
                 checkNotNull(customer);
-                //checkCustomer(customer);
                 accessControlService.checkPermission(getCurrentUser(), Resource.CUSTOMER, operation, customerId, customer);
                 return customer;
             } else {
@@ -297,59 +285,49 @@ public abstract class BaseController {
         }
     }
 
-    /*private void checkCustomer(Customer customer) throws ThingsboardException {
-        checkNotNull(customer);
-        checkTenantId(customer.getTenantId());
-    }*/
-
-    User checkUserId(UserId userId) throws ThingsboardException {
+    User checkUserId(UserId userId, Operation operation) throws ThingsboardException {
         try {
             validateId(userId, "Incorrect userId " + userId);
             User user = userService.findUserById(getCurrentUser().getTenantId(), userId);
-            checkUser(user);
+            checkNotNull(user);
+            accessControlService.checkPermission(getCurrentUser(), Resource.USER, operation, userId, user);
             return user;
         } catch (Exception e) {
             throw handleException(e, false);
         }
     }
 
-    private void checkUser(User user) throws ThingsboardException {
-        checkNotNull(user);
-        checkTenantId(user.getTenantId());
-        if (user.getAuthority() == Authority.CUSTOMER_USER) {
-            checkCustomerId(user.getCustomerId());
-        }
-    }
-
-    protected void checkEntityId(EntityId entityId) throws ThingsboardException {
+    protected void checkEntityId(EntityId entityId, Operation operation) throws ThingsboardException {
         try {
             checkNotNull(entityId);
             validateId(entityId.getId(), "Incorrect entityId " + entityId);
-            SecurityUser authUser = getCurrentUser();
             switch (entityId.getEntityType()) {
                 case DEVICE:
-                    checkDevice(deviceService.findDeviceById(authUser.getTenantId(), new DeviceId(entityId.getId())));
+                    checkDeviceId(new DeviceId(entityId.getId()), operation);
                     return;
                 case CUSTOMER:
-                    checkCustomerId(new CustomerId(entityId.getId()));
+                    checkCustomerId(new CustomerId(entityId.getId()), operation);
                     return;
                 case TENANT:
-                    checkTenantId(new TenantId(entityId.getId()));
+                    checkTenantId(new TenantId(entityId.getId()), operation);
                     return;
                 case RULE_CHAIN:
-                    checkRuleChain(new RuleChainId(entityId.getId()));
+                    checkRuleChain(new RuleChainId(entityId.getId()), operation);
+                    return;
+                case RULE_NODE:
+                    checkRuleNode(new RuleNodeId(entityId.getId()), operation);
                     return;
                 case ASSET:
-                    checkAsset(assetService.findAssetById(authUser.getTenantId(), new AssetId(entityId.getId())));
+                    checkAssetId(new AssetId(entityId.getId()), operation);
                     return;
                 case DASHBOARD:
-                    checkDashboardId(new DashboardId(entityId.getId()));
+                    checkDashboardId(new DashboardId(entityId.getId()), operation);
                     return;
                 case USER:
-                    checkUserId(new UserId(entityId.getId()));
+                    checkUserId(new UserId(entityId.getId()), operation);
                     return;
                 case ENTITY_VIEW:
-                    checkEntityViewId(new EntityViewId(entityId.getId()));
+                    checkEntityViewId(new EntityViewId(entityId.getId()), operation);
                     return;
                 default:
                     throw new IllegalArgumentException("Unsupported entity type: " + entityId.getEntityType());
@@ -364,7 +342,6 @@ public abstract class BaseController {
             validateId(deviceId, "Incorrect deviceId " + deviceId);
             Device device = deviceService.findDeviceById(getCurrentUser().getTenantId(), deviceId);
             checkNotNull(device);
-//            checkDevice(device);
             accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, operation, deviceId, device);
             return device;
         } catch (Exception e) {
@@ -372,18 +349,11 @@ public abstract class BaseController {
         }
     }
 
-    /*protected void checkDevice(Device device) throws ThingsboardException {
-        checkNotNull(device);
-        checkTenantId(device.getTenantId());
-        checkCustomerId(device.getCustomerId());
-    }*/
-
     protected EntityView checkEntityViewId(EntityViewId entityViewId, Operation operation) throws ThingsboardException {
         try {
             validateId(entityViewId, "Incorrect entityViewId " + entityViewId);
             EntityView entityView = entityViewService.findEntityViewById(getCurrentUser().getTenantId(), entityViewId);
             checkNotNull(entityView);
-            //checkEntityView(entityView);
             accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, operation, entityViewId, entityView);
             return entityView;
         } catch (Exception e) {
@@ -391,38 +361,24 @@ public abstract class BaseController {
         }
     }
 
-/*    protected void checkEntityView(EntityView entityView) throws ThingsboardException {
-        checkNotNull(entityView);
-        checkTenantId(entityView.getTenantId());
-        checkCustomerId(entityView.getCustomerId());
-    }*/
-
     Asset checkAssetId(AssetId assetId, Operation operation) throws ThingsboardException {
         try {
             validateId(assetId, "Incorrect assetId " + assetId);
             Asset asset = assetService.findAssetById(getCurrentUser().getTenantId(), assetId);
             checkNotNull(asset);
             accessControlService.checkPermission(getCurrentUser(), Resource.ASSET, operation, assetId, asset);
-            //checkAsset(asset);
             return asset;
         } catch (Exception e) {
             throw handleException(e, false);
         }
     }
 
-    /*protected void checkAsset(Asset asset) throws ThingsboardException {
-        checkNotNull(asset);
-        checkTenantId(asset.getTenantId());
-        checkCustomerId(asset.getCustomerId());
-    }*/
-
     Alarm checkAlarmId(AlarmId alarmId, Operation operation) throws ThingsboardException {
         try {
             validateId(alarmId, "Incorrect alarmId " + alarmId);
             Alarm alarm = alarmService.findAlarmByIdAsync(getCurrentUser().getTenantId(), alarmId).get();
             checkNotNull(alarm);
             accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, operation, alarmId, alarm);
-            //checkAlarm(alarm);
             return alarm;
         } catch (Exception e) {
             throw handleException(e, false);
@@ -435,67 +391,42 @@ public abstract class BaseController {
             AlarmInfo alarmInfo = alarmService.findAlarmInfoByIdAsync(getCurrentUser().getTenantId(), alarmId).get();
             checkNotNull(alarmInfo);
             accessControlService.checkPermission(getCurrentUser(), Resource.ALARM, operation, alarmId, alarmInfo);
-            //checkAlarm(alarmInfo);
             return alarmInfo;
         } catch (Exception e) {
             throw handleException(e, false);
         }
     }
 
-   /* protected void checkAlarm(Alarm alarm) throws ThingsboardException {
-        checkNotNull(alarm);
-        checkTenantId(alarm.getTenantId());
-    }*/
-
-    WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, boolean modify) throws ThingsboardException {
+    WidgetsBundle checkWidgetsBundleId(WidgetsBundleId widgetsBundleId, Operation operation) throws ThingsboardException {
         try {
             validateId(widgetsBundleId, "Incorrect widgetsBundleId " + widgetsBundleId);
             WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleById(getCurrentUser().getTenantId(), widgetsBundleId);
-            checkWidgetsBundle(widgetsBundle, modify);
+            checkNotNull(widgetsBundle);
+            accessControlService.checkPermission(getCurrentUser(), Resource.WIDGETS_BUNDLE, operation, widgetsBundleId, widgetsBundle);
             return widgetsBundle;
         } catch (Exception e) {
             throw handleException(e, false);
         }
     }
 
-    private void checkWidgetsBundle(WidgetsBundle widgetsBundle, boolean modify) throws ThingsboardException {
-        checkNotNull(widgetsBundle);
-        if (widgetsBundle.getTenantId() != null && !widgetsBundle.getTenantId().getId().equals(ModelConstants.NULL_UUID)) {
-            checkTenantId(widgetsBundle.getTenantId());
-        } else if (modify && getCurrentUser().getAuthority() != Authority.SYS_ADMIN) {
-            throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
-                    ThingsboardErrorCode.PERMISSION_DENIED);
-        }
-    }
-
-    WidgetType checkWidgetTypeId(WidgetTypeId widgetTypeId, boolean modify) throws ThingsboardException {
+    WidgetType checkWidgetTypeId(WidgetTypeId widgetTypeId, Operation operation) throws ThingsboardException {
         try {
             validateId(widgetTypeId, "Incorrect widgetTypeId " + widgetTypeId);
             WidgetType widgetType = widgetTypeService.findWidgetTypeById(getCurrentUser().getTenantId(), widgetTypeId);
-            checkWidgetType(widgetType, modify);
+            checkNotNull(widgetType);
+            accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, operation, widgetTypeId, widgetType);
             return widgetType;
         } catch (Exception e) {
             throw handleException(e, false);
         }
     }
 
-    void checkWidgetType(WidgetType widgetType, boolean modify) throws ThingsboardException {
-        checkNotNull(widgetType);
-        if (widgetType.getTenantId() != null && !widgetType.getTenantId().getId().equals(ModelConstants.NULL_UUID)) {
-            checkTenantId(widgetType.getTenantId());
-        } else if (modify && getCurrentUser().getAuthority() != Authority.SYS_ADMIN) {
-            throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
-                    ThingsboardErrorCode.PERMISSION_DENIED);
-        }
-    }
-
     Dashboard checkDashboardId(DashboardId dashboardId, Operation operation) throws ThingsboardException {
         try {
             validateId(dashboardId, "Incorrect dashboardId " + dashboardId);
             Dashboard dashboard = dashboardService.findDashboardById(getCurrentUser().getTenantId(), dashboardId);
             checkNotNull(dashboard);
             accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, operation, dashboardId, dashboard);
-            //checkDashboard(dashboard);
             return dashboard;
         } catch (Exception e) {
             throw handleException(e, false);
@@ -508,25 +439,12 @@ public abstract class BaseController {
             DashboardInfo dashboardInfo = dashboardService.findDashboardInfoById(getCurrentUser().getTenantId(), dashboardId);
             checkNotNull(dashboardInfo);
             accessControlService.checkPermission(getCurrentUser(), Resource.DASHBOARD, operation, dashboardId, dashboardInfo);
-            //checkDashboard(dashboardInfo);
             return dashboardInfo;
         } catch (Exception e) {
             throw handleException(e, false);
         }
     }
 
-    /*private void checkDashboard(DashboardInfo dashboard) throws ThingsboardException {
-        checkNotNull(dashboard);
-        checkTenantId(dashboard.getTenantId());
-        SecurityUser authUser = getCurrentUser();
-        if (authUser.getAuthority() == Authority.CUSTOMER_USER) {
-            if (!dashboard.isAssignedToCustomer(authUser.getCustomerId())) {
-                throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
-                        ThingsboardErrorCode.PERMISSION_DENIED);
-            }
-        }
-    }*/
-
     ComponentDescriptor checkComponentDescriptorByClazz(String clazz) throws ThingsboardException {
         try {
             log.debug("[{}] Lookup component descriptor", clazz);
@@ -554,24 +472,22 @@ public abstract class BaseController {
         }
     }
 
-    protected RuleChain checkRuleChain(RuleChainId ruleChainId) throws ThingsboardException {
-        checkNotNull(ruleChainId);
-        return checkRuleChain(ruleChainService.findRuleChainById(getCurrentUser().getTenantId(), ruleChainId));
-    }
-
-    protected RuleChain checkRuleChain(RuleChain ruleChain) throws ThingsboardException {
+    protected RuleChain checkRuleChain(RuleChainId ruleChainId, Operation operation) throws ThingsboardException {
+        validateId(ruleChainId, "Incorrect ruleChainId " + ruleChainId);
+        RuleChain ruleChain = ruleChainService.findRuleChainById(getCurrentUser().getTenantId(), ruleChainId);
         checkNotNull(ruleChain);
-        SecurityUser authUser = getCurrentUser();
-        TenantId tenantId = ruleChain.getTenantId();
-        validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
-        if (authUser.getAuthority() != Authority.TENANT_ADMIN ||
-                !authUser.getTenantId().equals(tenantId)) {
-            throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
-                    ThingsboardErrorCode.PERMISSION_DENIED);
-        }
+        accessControlService.checkPermission(getCurrentUser(), Resource.RULE_CHAIN, operation, ruleChainId, ruleChain);
         return ruleChain;
     }
 
+    protected RuleNode checkRuleNode(RuleNodeId ruleNodeId, Operation operation) throws ThingsboardException {
+        validateId(ruleNodeId, "Incorrect ruleNodeId " + ruleNodeId);
+        RuleNode ruleNode = ruleChainService.findRuleNodeById(getTenantId(), ruleNodeId);
+        checkNotNull(ruleNode);
+        checkRuleChain(ruleNode.getRuleChainId(), operation);
+        return ruleNode;
+    }
+
 
     protected String constructBaseUrl(HttpServletRequest request) {
         String scheme = request.getScheme();
diff --git a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
index 033c2a2..800fe23 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DashboardController.java
@@ -427,7 +427,7 @@ public class DashboardController extends BaseController {
             @RequestParam(required = false) String textOffset) throws ThingsboardException {
         try {
             TenantId tenantId = new TenantId(toUUID(strTenantId));
-            checkTenantId(tenantId);
+            checkTenantId(tenantId, Operation.READ);
             TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
             return checkNotNull(dashboardService.findDashboardsByTenantId(tenantId, pageLink));
         } catch (Exception e) {
diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
index 14c66af..b9a8551 100644
--- a/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/DeviceController.java
@@ -349,12 +349,11 @@ public class DeviceController extends BaseController {
         checkNotNull(query);
         checkNotNull(query.getParameters());
         checkNotNull(query.getDeviceTypes());
-        checkEntityId(query.getParameters().getEntityId());
+        checkEntityId(query.getParameters().getEntityId(), Operation.READ);
         try {
             List<Device> devices = checkNotNull(deviceService.findDevicesByQuery(getCurrentUser().getTenantId(), query).get());
             devices = devices.stream().filter(device -> {
                 try {
-                    //checkDevice(device);
                     accessControlService.checkPermission(getCurrentUser(), Resource.DEVICE, Operation.READ, device.getId(), device);
                     return true;
                 } catch (ThingsboardException e) {
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 04d35c5..68c6281 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityRelationController.java
@@ -35,6 +35,7 @@ import org.thingsboard.server.common.data.relation.EntityRelation;
 import org.thingsboard.server.common.data.relation.EntityRelationInfo;
 import org.thingsboard.server.common.data.relation.EntityRelationsQuery;
 import org.thingsboard.server.common.data.relation.RelationTypeGroup;
+import org.thingsboard.server.service.security.permission.Operation;
 
 import java.util.List;
 
@@ -55,8 +56,8 @@ public class EntityRelationController extends BaseController {
     public void saveRelation(@RequestBody EntityRelation relation) throws ThingsboardException {
         try {
             checkNotNull(relation);
-            checkEntityId(relation.getFrom());
-            checkEntityId(relation.getTo());
+            checkEntityId(relation.getFrom(), Operation.WRITE);
+            checkEntityId(relation.getTo(), Operation.WRITE);
             if (relation.getTypeGroup() == null) {
                 relation.setTypeGroup(RelationTypeGroup.COMMON);
             }
@@ -89,8 +90,8 @@ public class EntityRelationController extends BaseController {
         checkParameter(TO_TYPE, strToType);
         EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
         EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
-        checkEntityId(fromId);
-        checkEntityId(toId);
+        checkEntityId(fromId, Operation.WRITE);
+        checkEntityId(toId, Operation.WRITE);
         RelationTypeGroup relationTypeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
         EntityRelation relation = new EntityRelation(fromId, toId, strRelationType, relationTypeGroup);
         try {
@@ -119,7 +120,7 @@ public class EntityRelationController extends BaseController {
         checkParameter("entityId", strId);
         checkParameter("entityType", strType);
         EntityId entityId = EntityIdFactory.getByTypeAndId(strType, strId);
-        checkEntityId(entityId);
+        checkEntityId(entityId, Operation.WRITE);
         try {
             relationService.deleteEntityRelations(getTenantId(), entityId);
             logEntityAction(entityId, null, getCurrentUser().getCustomerId(), ActionType.RELATIONS_DELETED, null);
@@ -145,8 +146,8 @@ public class EntityRelationController extends BaseController {
             checkParameter(TO_TYPE, strToType);
             EntityId fromId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
             EntityId toId = EntityIdFactory.getByTypeAndId(strToType, strToId);
-            checkEntityId(fromId);
-            checkEntityId(toId);
+            checkEntityId(fromId, Operation.READ);
+            checkEntityId(toId, Operation.READ);
             RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
             return checkNotNull(relationService.getRelation(getTenantId(), fromId, toId, strRelationType, typeGroup));
         } catch (Exception e) {
@@ -163,7 +164,7 @@ public class EntityRelationController extends BaseController {
         checkParameter(FROM_ID, strFromId);
         checkParameter(FROM_TYPE, strFromType);
         EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
-        checkEntityId(entityId);
+        checkEntityId(entityId, Operation.READ);
         RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
         try {
             return checkNotNull(relationService.findByFrom(getTenantId(), entityId, typeGroup));
@@ -181,7 +182,7 @@ public class EntityRelationController extends BaseController {
         checkParameter(FROM_ID, strFromId);
         checkParameter(FROM_TYPE, strFromType);
         EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
-        checkEntityId(entityId);
+        checkEntityId(entityId, Operation.READ);
         RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
         try {
             return checkNotNull(relationService.findInfoByFrom(getTenantId(), entityId, typeGroup).get());
@@ -201,7 +202,7 @@ public class EntityRelationController extends BaseController {
         checkParameter(FROM_TYPE, strFromType);
         checkParameter(RELATION_TYPE, strRelationType);
         EntityId entityId = EntityIdFactory.getByTypeAndId(strFromType, strFromId);
-        checkEntityId(entityId);
+        checkEntityId(entityId, Operation.READ);
         RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
         try {
             return checkNotNull(relationService.findByFromAndType(getTenantId(), entityId, strRelationType, typeGroup));
@@ -219,7 +220,7 @@ public class EntityRelationController extends BaseController {
         checkParameter(TO_ID, strToId);
         checkParameter(TO_TYPE, strToType);
         EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
-        checkEntityId(entityId);
+        checkEntityId(entityId, Operation.READ);
         RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
         try {
             return checkNotNull(relationService.findByTo(getTenantId(), entityId, typeGroup));
@@ -237,7 +238,7 @@ public class EntityRelationController extends BaseController {
         checkParameter(TO_ID, strToId);
         checkParameter(TO_TYPE, strToType);
         EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
-        checkEntityId(entityId);
+        checkEntityId(entityId, Operation.READ);
         RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
         try {
             return checkNotNull(relationService.findInfoByTo(getTenantId(), entityId, typeGroup).get());
@@ -257,7 +258,7 @@ public class EntityRelationController extends BaseController {
         checkParameter(TO_TYPE, strToType);
         checkParameter(RELATION_TYPE, strRelationType);
         EntityId entityId = EntityIdFactory.getByTypeAndId(strToType, strToId);
-        checkEntityId(entityId);
+        checkEntityId(entityId, Operation.READ);
         RelationTypeGroup typeGroup = parseRelationTypeGroup(strRelationTypeGroup, RelationTypeGroup.COMMON);
         try {
             return checkNotNull(relationService.findByToAndType(getTenantId(), entityId, strRelationType, typeGroup));
@@ -273,7 +274,7 @@ public class EntityRelationController extends BaseController {
         checkNotNull(query);
         checkNotNull(query.getParameters());
         checkNotNull(query.getFilters());
-        checkEntityId(query.getParameters().getEntityId());
+        checkEntityId(query.getParameters().getEntityId(), Operation.READ);
         try {
             return checkNotNull(relationService.findByQuery(getTenantId(), query).get());
         } catch (Exception e) {
@@ -288,7 +289,7 @@ public class EntityRelationController extends BaseController {
         checkNotNull(query);
         checkNotNull(query.getParameters());
         checkNotNull(query.getFilters());
-        checkEntityId(query.getParameters().getEntityId());
+        checkEntityId(query.getParameters().getEntityId(), Operation.READ);
         try {
             return checkNotNull(relationService.findInfoByQuery(getTenantId(), query).get());
         } catch (Exception e) {
diff --git a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
index 0ac0e85..831cb9e 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EntityViewController.java
@@ -311,12 +311,11 @@ public class EntityViewController extends BaseController {
         checkNotNull(query);
         checkNotNull(query.getParameters());
         checkNotNull(query.getEntityViewTypes());
-        checkEntityId(query.getParameters().getEntityId());
+        checkEntityId(query.getParameters().getEntityId(), Operation.READ);
         try {
             List<EntityView> entityViews = checkNotNull(entityViewService.findEntityViewsByQuery(getTenantId(), query).get());
             entityViews = entityViews.stream().filter(entityView -> {
                 try {
-                    //checkEntityView(entityView);
                     accessControlService.checkPermission(getCurrentUser(), Resource.ENTITY_VIEW, Operation.READ, entityView.getId(), entityView);
                     return true;
                 } catch (ThingsboardException e) {
diff --git a/application/src/main/java/org/thingsboard/server/controller/EventController.java b/application/src/main/java/org/thingsboard/server/controller/EventController.java
index 66b01d3..941a2ca 100644
--- a/application/src/main/java/org/thingsboard/server/controller/EventController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/EventController.java
@@ -63,7 +63,7 @@ public class EventController extends BaseController {
             TenantId tenantId = new TenantId(toUUID(strTenantId));
 
             EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId);
-            checkEntityId(entityId);
+            checkEntityId(entityId, Operation.READ);
 
             TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
             return checkNotNull(eventService.findEvents(tenantId, entityId, eventType, pageLink));
@@ -91,7 +91,7 @@ public class EventController extends BaseController {
             TenantId tenantId = new TenantId(toUUID(strTenantId));
 
             EntityId entityId = EntityIdFactory.getByTypeAndId(strEntityType, strEntityId);
-            checkEntityId(entityId);
+            checkEntityId(entityId, Operation.READ);
 
             TimePageLink pageLink = createPageLink(limit, startTime, endTime, ascOrder, offset);
             return checkNotNull(eventService.findEvents(tenantId, entityId, pageLink));
diff --git a/application/src/main/java/org/thingsboard/server/controller/RpcController.java b/application/src/main/java/org/thingsboard/server/controller/RpcController.java
index a0d388c..aa1330d 100644
--- a/application/src/main/java/org/thingsboard/server/controller/RpcController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/RpcController.java
@@ -47,6 +47,7 @@ import org.thingsboard.server.service.rpc.FromDeviceRpcResponse;
 import org.thingsboard.server.service.rpc.LocalRequestMetaData;
 import org.thingsboard.server.service.security.AccessValidator;
 import org.thingsboard.server.service.security.model.SecurityUser;
+import org.thingsboard.server.service.security.permission.Operation;
 import org.thingsboard.server.service.telemetry.exception.ToErrorResponseEntity;
 
 import javax.annotation.Nullable;
@@ -118,7 +119,7 @@ public class RpcController extends BaseController {
             final DeferredResult<ResponseEntity> response = new DeferredResult<>();
             long timeout = System.currentTimeMillis() + (cmd.getTimeout() != null ? cmd.getTimeout() : DEFAULT_TIMEOUT);
             ToDeviceRpcRequestBody body = new ToDeviceRpcRequestBody(cmd.getMethodName(), cmd.getRequestData());
-            accessValidator.validate(currentUser, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() {
+            accessValidator.validate(currentUser, Operation.RPC_CALL, deviceId, new HttpValidationCallback(response, new FutureCallback<DeferredResult<ResponseEntity>>() {
                 @Override
                 public void onSuccess(@Nullable DeferredResult<ResponseEntity> result) {
                     ToDeviceRpcRequest rpcRequest = new ToDeviceRpcRequest(UUID.randomUUID(),
diff --git a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
index 4d88500..f4caa7c 100644
--- a/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/RuleChainController.java
@@ -52,6 +52,8 @@ import org.thingsboard.server.common.msg.TbMsgMetaData;
 import org.thingsboard.server.dao.event.EventService;
 import org.thingsboard.server.service.script.JsInvokeService;
 import org.thingsboard.server.service.script.RuleNodeJsScriptEngine;
+import org.thingsboard.server.service.security.permission.Operation;
+import org.thingsboard.server.service.security.permission.Resource;
 
 import java.util.List;
 import java.util.Map;
@@ -80,7 +82,7 @@ public class RuleChainController extends BaseController {
         checkParameter(RULE_CHAIN_ID, strRuleChainId);
         try {
             RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
-            return checkRuleChain(ruleChainId);
+            return checkRuleChain(ruleChainId, Operation.READ);
         } catch (Exception e) {
             throw handleException(e);
         }
@@ -93,7 +95,7 @@ public class RuleChainController extends BaseController {
         checkParameter(RULE_CHAIN_ID, strRuleChainId);
         try {
             RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
-            checkRuleChain(ruleChainId);
+            checkRuleChain(ruleChainId, Operation.READ);
             return ruleChainService.loadRuleChainMetaData(getTenantId(), ruleChainId);
         } catch (Exception e) {
             throw handleException(e);
@@ -108,6 +110,12 @@ public class RuleChainController extends BaseController {
         try {
             boolean created = ruleChain.getId() == null;
             ruleChain.setTenantId(getCurrentUser().getTenantId());
+
+            Operation operation = created ? Operation.CREATE : Operation.WRITE;
+
+            accessControlService.checkPermission(getCurrentUser(), Resource.RULE_CHAIN, operation,
+                    ruleChain.getId(), ruleChain);
+
             RuleChain savedRuleChain = checkNotNull(ruleChainService.saveRuleChain(ruleChain));
 
             actorService.onEntityStateChange(ruleChain.getTenantId(), savedRuleChain.getId(),
@@ -134,7 +142,7 @@ public class RuleChainController extends BaseController {
         checkParameter(RULE_CHAIN_ID, strRuleChainId);
         try {
             RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
-            RuleChain ruleChain = checkRuleChain(ruleChainId);
+            RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.WRITE);
             TenantId tenantId = getCurrentUser().getTenantId();
             RuleChain previousRootRuleChain = ruleChainService.getRootTenantRuleChain(tenantId);
             if (ruleChainService.setRootRuleChain(getTenantId(), ruleChainId)) {
@@ -171,7 +179,7 @@ public class RuleChainController extends BaseController {
     @ResponseBody
     public RuleChainMetaData saveRuleChainMetaData(@RequestBody RuleChainMetaData ruleChainMetaData) throws ThingsboardException {
         try {
-            RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId());
+            RuleChain ruleChain = checkRuleChain(ruleChainMetaData.getRuleChainId(), Operation.WRITE);
             RuleChainMetaData savedRuleChainMetaData = checkNotNull(ruleChainService.saveRuleChainMetaData(getTenantId(), ruleChainMetaData));
 
             actorService.onEntityStateChange(ruleChain.getTenantId(), ruleChain.getId(), ComponentLifecycleEvent.UPDATED);
@@ -214,7 +222,7 @@ public class RuleChainController extends BaseController {
         checkParameter(RULE_CHAIN_ID, strRuleChainId);
         try {
             RuleChainId ruleChainId = new RuleChainId(toUUID(strRuleChainId));
-            RuleChain ruleChain = checkRuleChain(ruleChainId);
+            RuleChain ruleChain = checkRuleChain(ruleChainId, Operation.DELETE);
 
             ruleChainService.deleteRuleChainById(getTenantId(), ruleChainId);
 
@@ -240,6 +248,7 @@ public class RuleChainController extends BaseController {
         checkParameter(RULE_NODE_ID, strRuleNodeId);
         try {
             RuleNodeId ruleNodeId = new RuleNodeId(toUUID(strRuleNodeId));
+            checkRuleNode(ruleNodeId, Operation.READ);
             TenantId tenantId = getCurrentUser().getTenantId();
             List<Event> events = eventService.findLatestEvents(tenantId, ruleNodeId, DataConstants.DEBUG_RULE_NODE, 2);
             JsonNode result = null;
diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
index bebd2cc..44553c8 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java
@@ -67,6 +67,7 @@ import org.thingsboard.server.common.transport.adaptor.JsonConverter;
 import org.thingsboard.server.dao.timeseries.TimeseriesService;
 import org.thingsboard.server.service.security.AccessValidator;
 import org.thingsboard.server.service.security.model.SecurityUser;
+import org.thingsboard.server.service.security.permission.Operation;
 import org.thingsboard.server.service.telemetry.AttributeData;
 import org.thingsboard.server.service.telemetry.TsData;
 import org.thingsboard.server.service.telemetry.exception.InvalidParametersException;
@@ -122,7 +123,7 @@ public class TelemetryController extends BaseController {
     @ResponseBody
     public DeferredResult<ResponseEntity> getAttributeKeys(
             @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException {
-        return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr, this::getAttributeKeysCallback);
+        return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr, this::getAttributeKeysCallback);
     }
 
     @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')")
@@ -131,7 +132,7 @@ public class TelemetryController extends BaseController {
     public DeferredResult<ResponseEntity> getAttributeKeysByScope(
             @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr
             , @PathVariable("scope") String scope) throws ThingsboardException {
-        return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
+        return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
                 (result, tenantId, entityId) -> getAttributeKeysCallback(result, tenantId, entityId, scope));
     }
 
@@ -142,7 +143,7 @@ public class TelemetryController extends BaseController {
             @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr,
             @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
         SecurityUser user = getCurrentUser();
-        return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
+        return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
                 (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, null, keysStr));
     }
 
@@ -154,7 +155,7 @@ public class TelemetryController extends BaseController {
             @PathVariable("scope") String scope,
             @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
         SecurityUser user = getCurrentUser();
-        return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
+        return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_ATTRIBUTES, entityType, entityIdStr,
                 (result, tenantId, entityId) -> getAttributeValuesCallback(result, user, entityId, scope, keysStr));
     }
 
@@ -163,7 +164,7 @@ public class TelemetryController extends BaseController {
     @ResponseBody
     public DeferredResult<ResponseEntity> getTimeseriesKeys(
             @PathVariable("entityType") String entityType, @PathVariable("entityId") String entityIdStr) throws ThingsboardException {
-        return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
+        return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
                 (result, tenantId, entityId) -> Futures.addCallback(tsService.findAllLatest(tenantId, entityId), getTsKeysToResponseCallback(result)));
     }
 
@@ -175,7 +176,7 @@ public class TelemetryController extends BaseController {
             @RequestParam(name = "keys", required = false) String keysStr) throws ThingsboardException {
         SecurityUser user = getCurrentUser();
 
-        return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
+        return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
                 (result, tenantId, entityId) -> getLatestTimeseriesValuesCallback(result, user, entityId, keysStr));
     }
 
@@ -192,7 +193,7 @@ public class TelemetryController extends BaseController {
             @RequestParam(name = "limit", defaultValue = "100") Integer limit,
             @RequestParam(name = "agg", defaultValue = "NONE") String aggStr
     ) throws ThingsboardException {
-        return accessValidator.validateEntityAndCallback(getCurrentUser(), entityType, entityIdStr,
+        return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.READ_TELEMETRY, entityType, entityIdStr,
                 (result, tenantId, entityId) -> {
                     // If interval is 0, convert this to a NONE aggregation, which is probably what the user really wanted
                     Aggregation agg = interval == 0L ? Aggregation.valueOf(Aggregation.NONE.name()) : Aggregation.valueOf(aggStr);
@@ -283,7 +284,7 @@ public class TelemetryController extends BaseController {
             deleteToTs = endTs;
         }
 
-        return accessValidator.validateEntityAndCallback(user, entityIdStr, (result, tenantId, entityId) -> {
+        return accessValidator.validateEntityAndCallback(user, Operation.WRITE_TELEMETRY, entityIdStr, (result, tenantId, entityId) -> {
             List<DeleteTsKvQuery> deleteTsKvQueries = new ArrayList<>();
             for (String key : keys) {
                 deleteTsKvQueries.add(new BaseDeleteTsKvQuery(key, deleteFromTs, deleteToTs, rewriteLatestIfDeleted));
@@ -336,7 +337,7 @@ public class TelemetryController extends BaseController {
         if (DataConstants.SERVER_SCOPE.equals(scope) ||
                 DataConstants.SHARED_SCOPE.equals(scope) ||
                 DataConstants.CLIENT_SCOPE.equals(scope)) {
-            return accessValidator.validateEntityAndCallback(getCurrentUser(), entityIdStr, (result, tenantId, entityId) -> {
+            return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_ATTRIBUTES, entityIdStr, (result, tenantId, entityId) -> {
                 ListenableFuture<List<Void>> future = attributesService.removeAll(user.getTenantId(), entityId, scope, keys);
                 Futures.addCallback(future, new FutureCallback<List<Void>>() {
                     @Override
@@ -375,7 +376,7 @@ public class TelemetryController extends BaseController {
                 return getImmediateDeferredResult("No attributes data found in request body!", HttpStatus.BAD_REQUEST);
             }
             SecurityUser user = getCurrentUser();
-            return accessValidator.validateEntityAndCallback(getCurrentUser(), entityIdSrc, (result, tenantId, entityId) -> {
+            return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_ATTRIBUTES, entityIdSrc, (result, tenantId, entityId) -> {
                 tsSubService.saveAndNotify(tenantId, entityId, scope, attributes, new FutureCallback<Void>() {
                     @Override
                     public void onSuccess(@Nullable Void tmp) {
@@ -424,7 +425,7 @@ public class TelemetryController extends BaseController {
             return getImmediateDeferredResult("No timeseries data found in request body!", HttpStatus.BAD_REQUEST);
         }
         SecurityUser user = getCurrentUser();
-        return accessValidator.validateEntityAndCallback(getCurrentUser(), entityIdSrc, (result, tenantId, entityId) -> {
+        return accessValidator.validateEntityAndCallback(getCurrentUser(), Operation.WRITE_TELEMETRY, entityIdSrc, (result, tenantId, entityId) -> {
             tsSubService.saveAndNotify(tenantId, entityId, entries, ttl, new FutureCallback<Void>() {
                 @Override
                 public void onSuccess(@Nullable Void tmp) {
diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java
index 155f0a1..a48bc65 100644
--- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java
@@ -35,6 +35,8 @@ import org.thingsboard.server.common.data.page.TextPageLink;
 import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent;
 import org.thingsboard.server.dao.tenant.TenantService;
 import org.thingsboard.server.service.install.InstallScripts;
+import org.thingsboard.server.service.security.permission.Operation;
+import org.thingsboard.server.service.security.permission.Resource;
 
 @RestController
 @RequestMapping("/api")
@@ -54,7 +56,7 @@ public class TenantController extends BaseController {
         checkParameter("tenantId", strTenantId);
         try {
             TenantId tenantId = new TenantId(toUUID(strTenantId));
-            checkTenantId(tenantId);
+            checkTenantId(tenantId, Operation.READ);
             return checkNotNull(tenantService.findTenantById(tenantId));
         } catch (Exception e) {
             throw handleException(e);
@@ -67,6 +69,12 @@ public class TenantController extends BaseController {
     public Tenant saveTenant(@RequestBody Tenant tenant) throws ThingsboardException {
         try {
             boolean newTenant = tenant.getId() == null;
+
+            Operation operation = newTenant ? Operation.CREATE : Operation.WRITE;
+
+            accessControlService.checkPermission(getCurrentUser(), tenant.getId(), Resource.TENANT, operation,
+                    tenant.getId());
+
             tenant = checkNotNull(tenantService.saveTenant(tenant));
             if (newTenant) {
                 installScripts.createDefaultRuleChains(tenant.getId());
@@ -84,6 +92,7 @@ public class TenantController extends BaseController {
         checkParameter("tenantId", strTenantId);
         try {
             TenantId tenantId = new TenantId(toUUID(strTenantId));
+            checkTenantId(tenantId, Operation.DELETE);
             tenantService.deleteTenant(tenantId);
 
             actorService.onEntityStateChange(tenantId, tenantId, ComponentLifecycleEvent.DELETED);
diff --git a/application/src/main/java/org/thingsboard/server/controller/UserController.java b/application/src/main/java/org/thingsboard/server/controller/UserController.java
index bea704e..ebf92bb 100644
--- a/application/src/main/java/org/thingsboard/server/controller/UserController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/UserController.java
@@ -49,6 +49,8 @@ import org.thingsboard.server.service.security.model.SecurityUser;
 import org.thingsboard.server.service.security.model.UserPrincipal;
 import org.thingsboard.server.service.security.model.token.JwtToken;
 import org.thingsboard.server.service.security.model.token.JwtTokenFactory;
+import org.thingsboard.server.service.security.permission.Operation;
+import org.thingsboard.server.service.security.permission.Resource;
 
 import javax.servlet.http.HttpServletRequest;
 
@@ -81,12 +83,7 @@ public class UserController extends BaseController {
         checkParameter(USER_ID, strUserId);
         try {
             UserId userId = new UserId(toUUID(strUserId));
-            SecurityUser authUser = getCurrentUser();
-            if (authUser.getAuthority() == Authority.CUSTOMER_USER && !authUser.getId().equals(userId)) {
-                throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
-                        ThingsboardErrorCode.PERMISSION_DENIED);
-            }
-            return checkUserId(userId);
+            return checkUserId(userId, Operation.READ);
         } catch (Exception e) {
             throw handleException(e);
         }
@@ -105,14 +102,13 @@ public class UserController extends BaseController {
     public JsonNode getUserToken(@PathVariable(USER_ID) String strUserId) throws ThingsboardException {
         checkParameter(USER_ID, strUserId);
         try {
-            UserId userId = new UserId(toUUID(strUserId));
-            SecurityUser authUser = getCurrentUser();
-            User user = userService.findUserById(authUser.getTenantId(), userId);
-            if (!userTokenAccessEnabled || (authUser.getAuthority() == Authority.SYS_ADMIN && user.getAuthority() != Authority.TENANT_ADMIN)
-                    || (authUser.getAuthority() == Authority.TENANT_ADMIN && !authUser.getTenantId().equals(user.getTenantId()))) {
+            if (!userTokenAccessEnabled) {
                 throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
                         ThingsboardErrorCode.PERMISSION_DENIED);
             }
+            UserId userId = new UserId(toUUID(strUserId));
+            SecurityUser authUser = getCurrentUser();
+            User user = checkUserId(userId, Operation.READ);
             UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail());
             UserCredentials credentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), userId);
             SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal);
@@ -135,17 +131,20 @@ public class UserController extends BaseController {
                          @RequestParam(required = false, defaultValue = "true") boolean sendActivationMail,
             HttpServletRequest request) throws ThingsboardException {
         try {
-            SecurityUser authUser = getCurrentUser();
-            if (authUser.getAuthority() == Authority.CUSTOMER_USER && !authUser.getId().equals(user.getId())) {
-                throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
-                        ThingsboardErrorCode.PERMISSION_DENIED);
-            }
-            boolean sendEmail = user.getId() == null && sendActivationMail;
+
             if (getCurrentUser().getAuthority() == Authority.TENANT_ADMIN) {
                 user.setTenantId(getCurrentUser().getTenantId());
             }
+
+            Operation operation = user.getId() == null ? Operation.CREATE : Operation.WRITE;
+
+            accessControlService.checkPermission(getCurrentUser(), Resource.USER, operation,
+                    user.getId(), user);
+
+            boolean sendEmail = user.getId() == null && sendActivationMail;
             User savedUser = checkNotNull(userService.saveUser(user));
             if (sendEmail) {
+                SecurityUser authUser = getCurrentUser();
                 UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), savedUser.getId());
                 String baseUrl = constructBaseUrl(request);
                 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
@@ -181,6 +180,10 @@ public class UserController extends BaseController {
             HttpServletRequest request) throws ThingsboardException {
         try {
             User user = checkNotNull(userService.findUserByEmail(getCurrentUser().getTenantId(), email));
+
+            accessControlService.checkPermission(getCurrentUser(), Resource.USER, Operation.READ,
+                    user.getId(), user);
+
             UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
             if (!userCredentials.isEnabled()) {
                 String baseUrl = constructBaseUrl(request);
@@ -204,13 +207,9 @@ public class UserController extends BaseController {
         checkParameter(USER_ID, strUserId);
         try {
             UserId userId = new UserId(toUUID(strUserId));
+            User user = checkUserId(userId, Operation.READ);
             SecurityUser authUser = getCurrentUser();
-            if (authUser.getAuthority() == Authority.CUSTOMER_USER && !authUser.getId().equals(userId)) {
-                throw new ThingsboardException(YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION,
-                        ThingsboardErrorCode.PERMISSION_DENIED);
-            }
-            User user = checkUserId(userId);
-            UserCredentials userCredentials = userService.findUserCredentialsByUserId(getCurrentUser().getTenantId(), user.getId());
+            UserCredentials userCredentials = userService.findUserCredentialsByUserId(authUser.getTenantId(), user.getId());
             if (!userCredentials.isEnabled()) {
                 String baseUrl = constructBaseUrl(request);
                 String activateUrl = String.format(ACTIVATE_URL_PATTERN, baseUrl,
@@ -231,7 +230,7 @@ public class UserController extends BaseController {
         checkParameter(USER_ID, strUserId);
         try {
             UserId userId = new UserId(toUUID(strUserId));
-            User user = checkUserId(userId);
+            User user = checkUserId(userId, Operation.DELETE);
             userService.deleteUser(getCurrentUser().getTenantId(), userId);
 
             logEntityAction(userId, user,
@@ -278,7 +277,7 @@ public class UserController extends BaseController {
         checkParameter("customerId", strCustomerId);
         try {
             CustomerId customerId = new CustomerId(toUUID(strCustomerId));
-            checkCustomerId(customerId);
+            checkCustomerId(customerId, Operation.READ);
             TextPageLink pageLink = createPageLink(limit, textSearch, idOffset, textOffset);
             TenantId tenantId = getCurrentUser().getTenantId();
             return checkNotNull(userService.findCustomerUsers(tenantId, customerId, pageLink));
diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
index 31f444d..689c37f 100644
--- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java
@@ -33,6 +33,8 @@ import org.thingsboard.server.common.data.page.TextPageLink;
 import org.thingsboard.server.common.data.security.Authority;
 import org.thingsboard.server.common.data.widget.WidgetsBundle;
 import org.thingsboard.server.dao.model.ModelConstants;
+import org.thingsboard.server.service.security.permission.Operation;
+import org.thingsboard.server.service.security.permission.Resource;
 
 import java.util.List;
 
@@ -47,7 +49,7 @@ public class WidgetsBundleController extends BaseController {
         checkParameter("widgetsBundleId", strWidgetsBundleId);
         try {
             WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
-            return checkWidgetsBundleId(widgetsBundleId, false);
+            return checkWidgetsBundleId(widgetsBundleId, Operation.READ);
         } catch (Exception e) {
             throw handleException(e);
         }
@@ -59,10 +61,16 @@ public class WidgetsBundleController extends BaseController {
     public WidgetsBundle saveWidgetsBundle(@RequestBody WidgetsBundle widgetsBundle) throws ThingsboardException {
         try {
             if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) {
-                widgetsBundle.setTenantId(new TenantId(ModelConstants.NULL_UUID));
+                widgetsBundle.setTenantId(TenantId.SYS_TENANT_ID);
             } else {
                 widgetsBundle.setTenantId(getCurrentUser().getTenantId());
             }
+
+            Operation operation = widgetsBundle.getId() == null ? Operation.CREATE : Operation.WRITE;
+
+            accessControlService.checkPermission(getCurrentUser(), Resource.WIDGETS_BUNDLE, operation,
+                    widgetsBundle.getId(), widgetsBundle);
+
             return checkNotNull(widgetsBundleService.saveWidgetsBundle(widgetsBundle));
         } catch (Exception e) {
             throw handleException(e);
@@ -76,7 +84,7 @@ public class WidgetsBundleController extends BaseController {
         checkParameter("widgetsBundleId", strWidgetsBundleId);
         try {
             WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId));
-            checkWidgetsBundleId(widgetsBundleId, true);
+            checkWidgetsBundleId(widgetsBundleId, Operation.DELETE);
             widgetsBundleService.deleteWidgetsBundle(getTenantId(), widgetsBundleId);
         } catch (Exception e) {
             throw handleException(e);
diff --git a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
index 9647450..a3651fa 100644
--- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
+++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
@@ -31,6 +31,8 @@ import org.thingsboard.server.common.data.id.WidgetTypeId;
 import org.thingsboard.server.common.data.security.Authority;
 import org.thingsboard.server.common.data.widget.WidgetType;
 import org.thingsboard.server.dao.model.ModelConstants;
+import org.thingsboard.server.service.security.permission.Operation;
+import org.thingsboard.server.service.security.permission.Resource;
 
 import java.util.List;
 
@@ -45,7 +47,7 @@ public class WidgetTypeController extends BaseController {
         checkParameter("widgetTypeId", strWidgetTypeId);
         try {
             WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
-            return checkWidgetTypeId(widgetTypeId, false);
+            return checkWidgetTypeId(widgetTypeId, Operation.READ);
         } catch (Exception e) {
             throw handleException(e);
         }
@@ -57,10 +59,16 @@ public class WidgetTypeController extends BaseController {
     public WidgetType saveWidgetType(@RequestBody WidgetType widgetType) throws ThingsboardException {
         try {
             if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN) {
-                widgetType.setTenantId(new TenantId(ModelConstants.NULL_UUID));
+                widgetType.setTenantId(TenantId.SYS_TENANT_ID);
             } else {
                 widgetType.setTenantId(getCurrentUser().getTenantId());
             }
+
+            Operation operation = widgetType.getId() == null ? Operation.CREATE : Operation.WRITE;
+
+            accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, operation,
+                    widgetType.getId(), widgetType);
+
             return checkNotNull(widgetTypeService.saveWidgetType(widgetType));
         } catch (Exception e) {
             throw handleException(e);
@@ -74,7 +82,7 @@ public class WidgetTypeController extends BaseController {
         checkParameter("widgetTypeId", strWidgetTypeId);
         try {
             WidgetTypeId widgetTypeId = new WidgetTypeId(toUUID(strWidgetTypeId));
-            checkWidgetTypeId(widgetTypeId, true);
+            checkWidgetTypeId(widgetTypeId, Operation.DELETE);
             widgetTypeService.deleteWidgetType(getCurrentUser().getTenantId(), widgetTypeId);
         } catch (Exception e) {
             throw handleException(e);
@@ -90,7 +98,7 @@ public class WidgetTypeController extends BaseController {
         try {
             TenantId tenantId;
             if (isSystem) {
-                tenantId = new TenantId(ModelConstants.NULL_UUID);
+                tenantId = TenantId.SYS_TENANT_ID;
             } else {
                 tenantId = getCurrentUser().getTenantId();
             }
@@ -115,7 +123,8 @@ public class WidgetTypeController extends BaseController {
                 tenantId = getCurrentUser().getTenantId();
             }
             WidgetType widgetType = widgetTypeService.findWidgetTypeByTenantIdBundleAliasAndAlias(tenantId, bundleAlias, alias);
-            checkWidgetType(widgetType, false);
+            checkNotNull(widgetType);
+            accessControlService.checkPermission(getCurrentUser(), Resource.WIDGET_TYPE, Operation.READ, widgetType.getId(), widgetType);
             return widgetType;
         } catch (Exception e) {
             throw handleException(e);
diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPremissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPremissions.java
index 4c67aa3..87fe80d 100644
--- a/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPremissions.java
+++ b/application/src/main/java/org/thingsboard/server/service/security/permission/CustomerUserPremissions.java
@@ -1,18 +1,29 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.thingsboard.server.service.security.permission;
 
-import org.thingsboard.server.common.data.Dashboard;
-import org.thingsboard.server.common.data.DashboardInfo;
-import org.thingsboard.server.common.data.HasCustomerId;
-import org.thingsboard.server.common.data.HasTenantId;
+import org.thingsboard.server.common.data.*;
 import org.thingsboard.server.common.data.id.DashboardId;
 import org.thingsboard.server.common.data.id.EntityId;
 import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.UserId;
+import org.thingsboard.server.common.data.security.Authority;
 import org.thingsboard.server.service.security.model.SecurityUser;
 
-import java.util.Arrays;
 import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
 
 public class CustomerUserPremissions extends HashMap<Resource, PermissionChecker> {
 
@@ -24,10 +35,13 @@ public class CustomerUserPremissions extends HashMap<Resource, PermissionChecker
         put(Resource.CUSTOMER, customerPermissionChecker);
         put(Resource.DASHBOARD, customerDashboardPermissionChecker);
         put(Resource.ENTITY_VIEW, customerEntityPermissionChecker);
-        put(Resource.TENANT, TenantAdminPermissions.tenantPermissionChecker);
+        put(Resource.USER, userPermissionChecker);
+        put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker);
+        put(Resource.WIDGET_TYPE, widgetsPermissionChecker);
     }
 
-    public static final PermissionChecker customerEntityPermissionChecker = new PermissionChecker.GenericPermissionChecker(Operation.READ) {
+    public static final PermissionChecker customerEntityPermissionChecker =
+            new PermissionChecker.GenericPermissionChecker(Operation.READ, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY) {
 
         @Override
         public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) {
@@ -49,7 +63,7 @@ public class CustomerUserPremissions extends HashMap<Resource, PermissionChecker
     };
 
     private static final PermissionChecker customerPermissionChecker =
-            new PermissionChecker.GenericPermissionChecker(Operation.READ) {
+            new PermissionChecker.GenericPermissionChecker(Operation.READ, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY) {
 
                 @Override
                 public boolean hasPermission(SecurityUser user, TenantId tenantId, Operation operation, EntityId entityId) {
@@ -65,7 +79,7 @@ public class CustomerUserPremissions extends HashMap<Resource, PermissionChecker
             };
 
     private static final PermissionChecker customerDashboardPermissionChecker =
-            new PermissionChecker.GenericPermissionChecker<DashboardInfo, DashboardId>(Operation.READ) {
+            new PermissionChecker.GenericPermissionChecker<DashboardInfo, DashboardId>(Operation.READ, Operation.READ_ATTRIBUTES, Operation.READ_TELEMETRY) {
 
                 @Override
                 public boolean hasPermission(SecurityUser user, Operation operation, DashboardId dashboardId, DashboardInfo dashboard) {
@@ -83,4 +97,34 @@ public class CustomerUserPremissions extends HashMap<Resource, PermissionChecker
                 }
 
             };
+
+    private static final PermissionChecker userPermissionChecker = new PermissionChecker<User, UserId>() {
+
+        @Override
+        public boolean hasPermission(SecurityUser user, Operation operation, UserId userId, User userEntity) {
+            if (userEntity.getAuthority() != Authority.CUSTOMER_USER) {
+                return false;
+            }
+            if (!user.getId().equals(userId)) {
+                return false;
+            }
+            return true;
+        }
+
+    };
+
+    private static final PermissionChecker widgetsPermissionChecker = new PermissionChecker.GenericPermissionChecker(Operation.READ) {
+
+        @Override
+        public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) {
+            if (!super.hasPermission(user, operation, entityId, entity)) {
+                return false;
+            }
+            if (entity.getTenantId() == null || entity.getTenantId().isNullUid() || user.getTenantId().equals(entity.getTenantId())) {
+                return true;
+            }
+            return true;
+        }
+
+    };
 }
diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/Operation.java b/application/src/main/java/org/thingsboard/server/service/security/permission/Operation.java
index d5254e7..e8ad7f0 100644
--- a/application/src/main/java/org/thingsboard/server/service/security/permission/Operation.java
+++ b/application/src/main/java/org/thingsboard/server/service/security/permission/Operation.java
@@ -17,6 +17,7 @@ package org.thingsboard.server.service.security.permission;
 
 public enum Operation {
 
-    ALL, CREATE, READ, WRITE, DELETE, ASSIGN_TO_CUSTOMER, UNASSIGN_FROM_CUSTOMER
+    ALL, CREATE, READ, WRITE, DELETE, ASSIGN_TO_CUSTOMER, UNASSIGN_FROM_CUSTOMER, RPC_CALL,
+    READ_ATTRIBUTES, WRITE_ATTRIBUTES, READ_TELEMETRY, WRITE_TELEMETRY
 
 }
diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java b/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java
index 921b7d9..3b14890 100644
--- a/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java
+++ b/application/src/main/java/org/thingsboard/server/service/security/permission/PermissionChecker.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.thingsboard.server.service.security.permission;
 
 import org.thingsboard.server.common.data.HasCustomerId;
diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java b/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java
index 8cf4dc2..7038b53 100644
--- a/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java
+++ b/application/src/main/java/org/thingsboard/server/service/security/permission/Resource.java
@@ -28,7 +28,10 @@ public enum Resource {
     DASHBOARD(EntityType.DASHBOARD),
     ENTITY_VIEW(EntityType.ENTITY_VIEW),
     TENANT(EntityType.TENANT),
-    RULE_CHAIN(EntityType.RULE_CHAIN);
+    RULE_CHAIN(EntityType.RULE_CHAIN),
+    USER(EntityType.USER),
+    WIDGETS_BUNDLE(EntityType.WIDGETS_BUNDLE),
+    WIDGET_TYPE(EntityType.WIDGET_TYPE);
 
     private final EntityType entityType;
 
diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java
index 251cb9b..285ebee 100644
--- a/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java
+++ b/application/src/main/java/org/thingsboard/server/service/security/permission/SysAdminPermissions.java
@@ -1,8 +1,26 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.thingsboard.server.service.security.permission;
 
 import org.thingsboard.server.common.data.HasTenantId;
+import org.thingsboard.server.common.data.User;
 import org.thingsboard.server.common.data.id.EntityId;
 import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.UserId;
+import org.thingsboard.server.common.data.security.Authority;
 import org.thingsboard.server.service.security.model.SecurityUser;
 
 import java.util.HashMap;
@@ -15,6 +33,9 @@ public class SysAdminPermissions extends HashMap<Resource, PermissionChecker> {
         put(Resource.DASHBOARD, new PermissionChecker.GenericPermissionChecker(Operation.READ));
         put(Resource.TENANT, PermissionChecker.allowAllPermissionChecker);
         put(Resource.RULE_CHAIN, systemEntityPermissionChecker);
+        put(Resource.USER, userPermissionChecker);
+        put(Resource.WIDGETS_BUNDLE, systemEntityPermissionChecker);
+        put(Resource.WIDGET_TYPE, systemEntityPermissionChecker);
     }
 
     private static final PermissionChecker systemEntityPermissionChecker = new PermissionChecker<HasTenantId, EntityId>() {
@@ -36,4 +57,17 @@ public class SysAdminPermissions extends HashMap<Resource, PermissionChecker> {
             return true;
         }
     };
+
+    private static final PermissionChecker userPermissionChecker = new PermissionChecker<User, UserId>() {
+
+        @Override
+        public boolean hasPermission(SecurityUser user, Operation operation, UserId userId, User userEntity) {
+            if (userEntity.getAuthority() == Authority.CUSTOMER_USER) {
+                return false;
+            }
+            return true;
+        }
+
+    };
+
 }
diff --git a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java
index c8e208f..c5d9f37 100644
--- a/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java
+++ b/application/src/main/java/org/thingsboard/server/service/security/permission/TenantAdminPermissions.java
@@ -1,8 +1,26 @@
+/**
+ * Copyright © 2016-2018 The Thingsboard Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.thingsboard.server.service.security.permission;
 
 import org.thingsboard.server.common.data.HasTenantId;
+import org.thingsboard.server.common.data.User;
 import org.thingsboard.server.common.data.id.EntityId;
 import org.thingsboard.server.common.data.id.TenantId;
+import org.thingsboard.server.common.data.id.UserId;
+import org.thingsboard.server.common.data.security.Authority;
 import org.thingsboard.server.service.security.model.SecurityUser;
 
 import java.util.HashMap;
@@ -19,6 +37,9 @@ public class TenantAdminPermissions extends HashMap<Resource, PermissionChecker>
         put(Resource.ENTITY_VIEW, tenantEntityPermissionChecker);
         put(Resource.TENANT, tenantPermissionChecker);
         put(Resource.RULE_CHAIN, tenantEntityPermissionChecker);
+        put(Resource.USER, userPermissionChecker);
+        put(Resource.WIDGETS_BUNDLE, widgetsPermissionChecker);
+        put(Resource.WIDGET_TYPE, widgetsPermissionChecker);
     }
 
     public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker<HasTenantId, EntityId>() {
@@ -56,4 +77,34 @@ public class TenantAdminPermissions extends HashMap<Resource, PermissionChecker>
                 }
 
             };
+
+    private static final PermissionChecker userPermissionChecker = new PermissionChecker<User, UserId>() {
+
+        @Override
+        public boolean hasPermission(SecurityUser user, Operation operation, UserId userId, User userEntity) {
+            if (userEntity.getAuthority() == Authority.SYS_ADMIN) {
+                return false;
+            }
+            if (!user.getTenantId().equals(userEntity.getTenantId())) {
+                return false;
+            }
+            return true;
+        }
+
+    };
+
+    private static final PermissionChecker widgetsPermissionChecker = new PermissionChecker<HasTenantId, EntityId>() {
+
+        @Override
+        public boolean hasPermission(SecurityUser user, Operation operation, EntityId entityId, HasTenantId entity) {
+            if (entity.getTenantId() == null || entity.getTenantId().isNullUid()) {
+                return operation == Operation.READ;
+            }
+            if (!user.getTenantId().equals(entity.getTenantId())) {
+                return false;
+            }
+            return true;
+        }
+
+    };
 }
diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java
index 6bda32d..83e7cff 100644
--- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java
+++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetryWebSocketService.java
@@ -48,6 +48,7 @@ import org.thingsboard.server.service.security.ValidationCallback;
 import org.thingsboard.server.service.security.ValidationResult;
 import org.thingsboard.server.service.security.ValidationResultCode;
 import org.thingsboard.server.service.security.model.UserPrincipal;
+import org.thingsboard.server.service.security.permission.Operation;
 import org.thingsboard.server.service.telemetry.cmd.AttributesSubscriptionCmd;
 import org.thingsboard.server.service.telemetry.cmd.GetHistoryCmd;
 import org.thingsboard.server.service.telemetry.cmd.SubscriptionCmd;
@@ -354,9 +355,9 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
         };
 
         if (StringUtils.isEmpty(cmd.getScope())) {
-            accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, keys, callback));
+            accessValidator.validate(sessionRef.getSecurityCtx(), Operation.READ_ATTRIBUTES, entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, keys, callback));
         } else {
-            accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, cmd.getScope(), keys, callback));
+            accessValidator.validate(sessionRef.getSecurityCtx(), Operation.READ_ATTRIBUTES, entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, cmd.getScope(), keys, callback));
         }
     }
 
@@ -406,7 +407,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
                 sendWsMsg(sessionRef, update);
             }
         };
-        accessValidator.validate(sessionRef.getSecurityCtx(), entityId,
+        accessValidator.validate(sessionRef.getSecurityCtx(), Operation.READ_TELEMETRY, entityId,
                 on(r -> Futures.addCallback(tsService.findAll(sessionRef.getSecurityCtx().getTenantId(), entityId, queries), callback, executor), callback::onFailure));
     }
 
@@ -436,9 +437,9 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
 
 
         if (StringUtils.isEmpty(cmd.getScope())) {
-            accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, callback));
+            accessValidator.validate(sessionRef.getSecurityCtx(), Operation.READ_ATTRIBUTES, entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, callback));
         } else {
-            accessValidator.validate(sessionRef.getSecurityCtx(), entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, cmd.getScope(), callback));
+            accessValidator.validate(sessionRef.getSecurityCtx(), Operation.READ_ATTRIBUTES, entityId, getAttributesFetchCallback(sessionRef.getSecurityCtx().getTenantId(), entityId, cmd.getScope(), callback));
         }
     }
 
@@ -474,14 +475,14 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
                     getLimit(cmd.getLimit()), getAggregation(cmd.getAgg()))).collect(Collectors.toList());
 
             final FutureCallback<List<TsKvEntry>> callback = getSubscriptionCallback(sessionRef, cmd, sessionId, entityId, startTs, keys);
-            accessValidator.validate(sessionRef.getSecurityCtx(), entityId,
+            accessValidator.validate(sessionRef.getSecurityCtx(), Operation.READ_TELEMETRY, entityId,
                     on(r -> Futures.addCallback(tsService.findAll(sessionRef.getSecurityCtx().getTenantId(), entityId, queries), callback, executor), callback::onFailure));
         } else {
             List<String> keys = new ArrayList<>(getKeys(cmd).orElse(Collections.emptySet()));
             startTs = System.currentTimeMillis();
             log.debug("[{}] fetching latest timeseries data for keys: ({}) for device : {}", sessionId, cmd.getKeys(), entityId);
             final FutureCallback<List<TsKvEntry>> callback = getSubscriptionCallback(sessionRef, cmd, sessionId, entityId, startTs, keys);
-            accessValidator.validate(sessionRef.getSecurityCtx(), entityId,
+            accessValidator.validate(sessionRef.getSecurityCtx(), Operation.READ_TELEMETRY, entityId,
                     on(r -> Futures.addCallback(tsService.findLatest(sessionRef.getSecurityCtx().getTenantId(), entityId, keys), callback, executor), callback::onFailure));
         }
     }
@@ -511,7 +512,7 @@ public class DefaultTelemetryWebSocketService implements TelemetryWebSocketServi
                 sendWsMsg(sessionRef, update);
             }
         };
-        accessValidator.validate(sessionRef.getSecurityCtx(), entityId,
+        accessValidator.validate(sessionRef.getSecurityCtx(), Operation.READ_TELEMETRY, entityId,
                 on(r -> Futures.addCallback(tsService.findAllLatest(sessionRef.getSecurityCtx().getTenantId(), entityId), callback, executor), callback::onFailure));
     }
 
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
index ef4994a..2cf8374 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java
@@ -19,5 +19,5 @@ package org.thingsboard.server.common.data;
  * @author Andrew Shvayka
  */
 public enum EntityType {
-    TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW
+    TENANT, CUSTOMER, USER, DASHBOARD, ASSET, DEVICE, ALARM, RULE_CHAIN, RULE_NODE, ENTITY_VIEW, WIDGETS_BUNDLE, WIDGET_TYPE
 }
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 4e35c0b..1ba1af6 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
@@ -59,6 +59,10 @@ public class EntityIdFactory {
                 return new RuleNodeId(uuid);
             case ENTITY_VIEW:
                 return new EntityViewId(uuid);
+            case WIDGETS_BUNDLE:
+                return new WidgetsBundleId(uuid);
+            case WIDGET_TYPE:
+                return new WidgetTypeId(uuid);
         }
         throw new IllegalArgumentException("EntityType " + type + " is not supported!");
     }
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetsBundleId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetsBundleId.java
index 7d8e853..c0a5380 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetsBundleId.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetsBundleId.java
@@ -18,9 +18,11 @@ package org.thingsboard.server.common.data.id;
 import java.util.UUID;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import org.thingsboard.server.common.data.EntityType;
 
-public final class WidgetsBundleId extends UUIDBased {
+public final class WidgetsBundleId extends UUIDBased implements EntityId {
 
     private static final long serialVersionUID = 1L;
 
@@ -29,4 +31,9 @@ public final class WidgetsBundleId extends UUIDBased {
         super(id);
     }
 
+    @JsonIgnore
+    @Override
+    public EntityType getEntityType() {
+        return EntityType.WIDGETS_BUNDLE;
+    }
 }
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetTypeId.java b/common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetTypeId.java
index df04222..23cf1ba 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetTypeId.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/id/WidgetTypeId.java
@@ -18,9 +18,11 @@ package org.thingsboard.server.common.data.id;
 import java.util.UUID;
 
 import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import com.fasterxml.jackson.annotation.JsonProperty;
+import org.thingsboard.server.common.data.EntityType;
 
-public final class WidgetTypeId extends UUIDBased {
+public final class WidgetTypeId extends UUIDBased implements EntityId {
 
     private static final long serialVersionUID = 1L;
 
@@ -29,4 +31,9 @@ public final class WidgetTypeId extends UUIDBased {
         super(id);
     }
 
+    @JsonIgnore
+    @Override
+    public EntityType getEntityType() {
+        return EntityType.WIDGET_TYPE;
+    }
 }
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java
index 01112b3..5048617 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetsBundle.java
@@ -15,13 +15,14 @@
  */
 package org.thingsboard.server.common.data.widget;
 
+import org.thingsboard.server.common.data.HasTenantId;
 import org.thingsboard.server.common.data.SearchTextBased;
 import org.thingsboard.server.common.data.id.TenantId;
 import org.thingsboard.server.common.data.id.WidgetsBundleId;
 
 import java.util.Arrays;
 
-public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> {
+public class WidgetsBundle extends SearchTextBased<WidgetsBundleId> implements HasTenantId {
 
     private static final long serialVersionUID = -7627368878362410489L;
 
diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java
index fc21bdc..e488a5a 100644
--- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java
+++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetType.java
@@ -18,11 +18,12 @@ package org.thingsboard.server.common.data.widget;
 import com.fasterxml.jackson.databind.JsonNode;
 import lombok.EqualsAndHashCode;
 import org.thingsboard.server.common.data.BaseData;
+import org.thingsboard.server.common.data.HasTenantId;
 import org.thingsboard.server.common.data.id.TenantId;
 import org.thingsboard.server.common.data.id.WidgetTypeId;
 
 @EqualsAndHashCode(callSuper = true)
-public class WidgetType extends BaseData<WidgetTypeId> {
+public class WidgetType extends BaseData<WidgetTypeId> implements HasTenantId {
 
     private static final long serialVersionUID = 8388684344603660756L;
 
diff --git a/msa/js-executor/package-lock.json b/msa/js-executor/package-lock.json
index f232cca..1af1630 100644
--- a/msa/js-executor/package-lock.json
+++ b/msa/js-executor/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "thingsboard-js-executor",
-  "version": "2.2.1",
+  "version": "2.3.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/msa/web-ui/package-lock.json b/msa/web-ui/package-lock.json
index 11cf32b..c50ee7d 100644
--- a/msa/web-ui/package-lock.json
+++ b/msa/web-ui/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "thingsboard-web-ui",
-  "version": "2.2.1",
+  "version": "2.3.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
diff --git a/ui/package-lock.json b/ui/package-lock.json
index 93adbd1..7c0604d 100644
--- a/ui/package-lock.json
+++ b/ui/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "thingsboard",
-  "version": "2.2.1",
+  "version": "2.3.0",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {