diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java index 97d43ee892..ea8e408713 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultAlarmQueryRepository.java @@ -124,7 +124,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { AlarmDataQuery query, Collection orderedEntityIds) { return transactionTemplate.execute(status -> { AlarmDataPageLink pageLink = query.getPageLink(); - QueryContext ctx = new QueryContext(); + QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, EntityType.ALARM)); ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList())); StringBuilder selectPart = new StringBuilder(FIELDS_SELECTION); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index 9572b72528..b2f125063c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -227,11 +227,11 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @Override public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) { EntityType entityType = resolveEntityType(query.getEntityFilter()); - QueryContext ctx = new QueryContext(); + QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, entityType)); ctx.append("select count(e.id) from "); - ctx.append(addEntityTableQuery(ctx, query.getEntityFilter(), entityType)); + ctx.append(addEntityTableQuery(ctx, query.getEntityFilter())); ctx.append(" e where "); - ctx.append(buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), Collections.emptyList(), entityType)); + ctx.append(buildEntityWhere(ctx, query.getEntityFilter(), Collections.emptyList())); // log.error("QUERY: {}", ctx.getQuery()); // Arrays.asList(ctx.getParameterNames()).forEach(param -> log.error("QUERY PARAM: {}->{}", param, ctx.getValue(param))); return transactionTemplate.execute(status -> jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class)); @@ -240,8 +240,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @Override public PageData findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) { return transactionTemplate.execute(status -> { - QueryContext ctx = new QueryContext(); EntityType entityType = resolveEntityType(query.getEntityFilter()); + QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, entityType)); EntityDataPageLink pageLink = query.getPageLink(); List mappings = EntityKeyMapping.prepareKeyMapping(query); @@ -264,9 +264,9 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { .collect(Collectors.toList()); - String entityWhereClause = DefaultEntityQueryRepository.this.buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), entityFieldsFiltersMapping, entityType); + String entityWhereClause = DefaultEntityQueryRepository.this.buildEntityWhere(ctx, query.getEntityFilter(), entityFieldsFiltersMapping); String latestJoins = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings); - String whereClause = DefaultEntityQueryRepository.this.buildWhere(ctx, latestFiltersMapping, query.getEntityFilter().getType(), entityType); + String whereClause = DefaultEntityQueryRepository.this.buildWhere(ctx, latestFiltersMapping, query.getEntityFilter().getType()); String textSearchQuery = DefaultEntityQueryRepository.this.buildTextSearchQuery(ctx, selectionMapping, pageLink.getTextSearch()); String entityFieldsSelection = EntityKeyMapping.buildSelections(entityFieldsSelectionMapping, query.getEntityFilter().getType(), entityType); String entityTypeStr; @@ -289,7 +289,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { String fromClause = String.format("from (select %s from (select %s from %s e where %s) entities %s %s) result %s", topSelection, entityFieldsSelection, - addEntityTableQuery(ctx, query.getEntityFilter(), entityType), + addEntityTableQuery(ctx, query.getEntityFilter()), entityWhereClause, latestJoins, whereClause, @@ -323,15 +323,10 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { }); } - private String buildEntityWhere(QueryContext ctx, - TenantId tenantId, - CustomerId customerId, - EntityFilter entityFilter, - List entityFieldsFilters, - EntityType entityType) { - String permissionQuery = this.buildPermissionQuery(ctx, entityFilter, tenantId, customerId, entityType); + private String buildEntityWhere(QueryContext ctx, EntityFilter entityFilter, List entityFieldsFilters) { + String permissionQuery = this.buildPermissionQuery(ctx, entityFilter); String entityFilterQuery = this.buildEntityFilterQuery(ctx, entityFilter); - String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType(), entityType); + String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType()); String result = permissionQuery; if (!entityFilterQuery.isEmpty()) { result += " and " + entityFilterQuery; @@ -342,28 +337,28 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { return result; } - private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter, TenantId tenantId, CustomerId customerId, EntityType entityType) { + private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter) { switch (entityFilter.getType()) { case RELATIONS_QUERY: case DEVICE_SEARCH_QUERY: case ASSET_SEARCH_QUERY: case ENTITY_VIEW_SEARCH_QUERY: - return this.defaultPermissionQuery(ctx, tenantId, customerId, entityType); + return this.defaultPermissionQuery(ctx); default: - if (entityType == EntityType.TENANT) { - ctx.addUuidParameter("permissions_tenant_id", tenantId.getId()); + if (ctx.getEntityType() == EntityType.TENANT) { + ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId()); return "e.id=:permissions_tenant_id"; } else { - return this.defaultPermissionQuery(ctx, tenantId, customerId, entityType); + return this.defaultPermissionQuery(ctx); } } } - private String defaultPermissionQuery(QueryContext ctx, TenantId tenantId, CustomerId customerId, EntityType entityType) { - ctx.addUuidParameter("permissions_tenant_id", tenantId.getId()); - if (customerId != null && !customerId.isNullUid()) { - ctx.addUuidParameter("permissions_customer_id", customerId.getId()); - if (entityType == EntityType.CUSTOMER) { + private String defaultPermissionQuery(QueryContext ctx) { + ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId()); + if (ctx.getCustomerId() != null && !ctx.getCustomerId().isNullUid()) { + ctx.addUuidParameter("permissions_customer_id", ctx.getCustomerId().getId()); + if (ctx.getEntityType() == EntityType.CUSTOMER) { return "e.tenant_id=:permissions_tenant_id and e.id=:permissions_customer_id"; } else { return "e.tenant_id=:permissions_tenant_id and e.customer_id=:permissions_customer_id"; @@ -395,7 +390,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { } } - private String addEntityTableQuery(QueryContext ctx, EntityFilter entityFilter, EntityType entityType) { + private String addEntityTableQuery(QueryContext ctx, EntityFilter entityFilter) { switch (entityFilter.getType()) { case RELATIONS_QUERY: return relationQuery(ctx, (RelationsQueryFilter) entityFilter); @@ -409,7 +404,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { EntityViewSearchQueryFilter entityViewQuery = (EntityViewSearchQueryFilter) entityFilter; return entitySearchQuery(ctx, entityViewQuery, EntityType.ENTITY_VIEW, entityViewQuery.getEntityViewTypes()); default: - return entityTableMap.get(entityType); + return entityTableMap.get(ctx.getEntityType()); } } @@ -505,8 +500,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { return from; } - private String buildWhere(QueryContext ctx, List latestFiltersMapping, EntityFilterType filterType, EntityType entityType) { - String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping, filterType, entityType); + private String buildWhere(QueryContext ctx, List latestFiltersMapping, EntityFilterType filterType) { + String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping, filterType); if (!StringUtils.isEmpty(latestFilters)) { return String.format("where %s", latestFilters); } else { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 260670f692..c1b523720b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -214,11 +214,11 @@ public class EntityKeyMapping { return alias; } - public Stream toQueries(QueryContext ctx, EntityFilterType filterType, EntityType entityType) { + public Stream toQueries(QueryContext ctx, EntityFilterType filterType) { if (hasFilter()) { String keyAlias = entityKey.getType().equals(EntityKeyType.ENTITY_FIELD) ? "e" : alias; return keyFilters.stream().map(keyFilter -> - this.buildKeyQuery(ctx, keyAlias, keyFilter, filterType, entityType)); + this.buildKeyQuery(ctx, keyAlias, keyFilter, filterType)); } else { return null; } @@ -271,8 +271,8 @@ public class EntityKeyMapping { Collectors.joining(" ")); } - public static String buildQuery(QueryContext ctx, List mappings, EntityFilterType filterType, EntityType entityType) { - return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx, filterType, entityType)).filter(Objects::nonNull).collect( + public static String buildQuery(QueryContext ctx, List mappings, EntityFilterType filterType) { + return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx, filterType)).filter(Objects::nonNull).collect( Collectors.joining(" AND ")); } @@ -385,33 +385,33 @@ public class EntityKeyMapping { } private String buildKeyQuery(QueryContext ctx, String alias, KeyFilter keyFilter, - EntityFilterType filterType, EntityType entityType) { - return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate(), filterType, entityType); + EntityFilterType filterType) { + return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate(), filterType); } private String buildPredicateQuery(QueryContext ctx, String alias, EntityKey key, - KeyFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) { + KeyFilterPredicate predicate, EntityFilterType filterType) { if (predicate.getType().equals(FilterPredicateType.COMPLEX)) { - return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate, filterType, entityType); + return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate, filterType); } else { - return this.buildSimplePredicateQuery(ctx, alias, key, predicate, filterType, entityType); + return this.buildSimplePredicateQuery(ctx, alias, key, predicate, filterType); } } private String buildComplexPredicateQuery(QueryContext ctx, String alias, EntityKey key, - ComplexFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) { + ComplexFilterPredicate predicate, EntityFilterType filterType) { return predicate.getPredicates().stream() - .map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate, filterType, entityType)) + .map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate, filterType)) .filter(Objects::nonNull).collect(Collectors.joining( " " + predicate.getOperation().name() + " " )); } private String buildSimplePredicateQuery(QueryContext ctx, String alias, EntityKey key, - KeyFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) { + KeyFilterPredicate predicate, EntityFilterType filterType) { if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) { - Set existingEntityFields = getExistingEntityFields(filterType, entityType); - String entityFieldAlias = getEntityFieldAlias(filterType, entityType); + Set existingEntityFields = getExistingEntityFields(filterType, ctx.getEntityType()); + String entityFieldAlias = getEntityFieldAlias(filterType, ctx.getEntityType()); String column = null; if (existingEntityFields.contains(entityFieldAlias)) { column = entityFieldColumnMap.get(entityFieldAlias); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/QueryContext.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/QueryContext.java index 4ffaedbbc9..1399967b27 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/QueryContext.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/QueryContext.java @@ -17,6 +17,9 @@ package org.thingsboard.server.dao.sql.query; import org.hibernate.type.PostgresUUIDType; import org.springframework.jdbc.core.namedparam.SqlParameterSource; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.TenantId; import java.sql.Types; import java.util.HashMap; @@ -27,10 +30,12 @@ import java.util.UUID; public class QueryContext implements SqlParameterSource { private static final PostgresUUIDType UUID_TYPE = new PostgresUUIDType(); + private final QuerySecurityContext securityCtx; private final StringBuilder query; private final Map params; - public QueryContext() { + public QueryContext(QuerySecurityContext securityCtx) { + this.securityCtx = securityCtx; query = new StringBuilder(); params = new HashMap<>(); } @@ -123,4 +128,16 @@ public class QueryContext implements SqlParameterSource { this.name = name; } } + + public TenantId getTenantId() { + return securityCtx.getTenantId(); + } + + public CustomerId getCustomerId() { + return securityCtx.getCustomerId(); + } + + public EntityType getEntityType() { + return securityCtx.getEntityType(); + } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/QuerySecurityContext.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/QuerySecurityContext.java new file mode 100644 index 0000000000..7cabb693c1 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/QuerySecurityContext.java @@ -0,0 +1,42 @@ +/** + * Copyright © 2016-2020 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.dao.sql.query; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.hibernate.type.PostgresUUIDType; +import org.springframework.jdbc.core.namedparam.SqlParameterSource; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.CustomerId; +import org.thingsboard.server.common.data.id.TenantId; + +import java.sql.Types; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +@AllArgsConstructor +public class QuerySecurityContext { + + @Getter + private final TenantId tenantId; + @Getter + private final CustomerId customerId; + @Getter + private final EntityType entityType; + +} \ No newline at end of file