Commit c698b92397b66db24e7aafd040203d34140113a5

Authored by Igor Kulikov
2 parents ea3c6f34 436aedef

Merge branch 'master' of github.com:thingsboard/thingsboard

@@ -124,7 +124,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository { @@ -124,7 +124,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
124 AlarmDataQuery query, Collection<EntityId> orderedEntityIds) { 124 AlarmDataQuery query, Collection<EntityId> orderedEntityIds) {
125 return transactionTemplate.execute(status -> { 125 return transactionTemplate.execute(status -> {
126 AlarmDataPageLink pageLink = query.getPageLink(); 126 AlarmDataPageLink pageLink = query.getPageLink();
127 - QueryContext ctx = new QueryContext(); 127 + QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, EntityType.ALARM));
128 ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList())); 128 ctx.addUuidListParameter("entity_ids", orderedEntityIds.stream().map(EntityId::getId).collect(Collectors.toList()));
129 129
130 StringBuilder selectPart = new StringBuilder(FIELDS_SELECTION); 130 StringBuilder selectPart = new StringBuilder(FIELDS_SELECTION);
@@ -227,11 +227,11 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -227,11 +227,11 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
227 @Override 227 @Override
228 public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) { 228 public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) {
229 EntityType entityType = resolveEntityType(query.getEntityFilter()); 229 EntityType entityType = resolveEntityType(query.getEntityFilter());
230 - QueryContext ctx = new QueryContext(); 230 + QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, entityType));
231 ctx.append("select count(e.id) from "); 231 ctx.append("select count(e.id) from ");
232 - ctx.append(addEntityTableQuery(ctx, query.getEntityFilter(), entityType)); 232 + ctx.append(addEntityTableQuery(ctx, query.getEntityFilter()));
233 ctx.append(" e where "); 233 ctx.append(" e where ");
234 - ctx.append(buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), Collections.emptyList(), entityType)); 234 + ctx.append(buildEntityWhere(ctx, query.getEntityFilter(), Collections.emptyList()));
235 // log.error("QUERY: {}", ctx.getQuery()); 235 // log.error("QUERY: {}", ctx.getQuery());
236 // Arrays.asList(ctx.getParameterNames()).forEach(param -> log.error("QUERY PARAM: {}->{}", param, ctx.getValue(param))); 236 // Arrays.asList(ctx.getParameterNames()).forEach(param -> log.error("QUERY PARAM: {}->{}", param, ctx.getValue(param)));
237 return transactionTemplate.execute(status -> jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class)); 237 return transactionTemplate.execute(status -> jdbcTemplate.queryForObject(ctx.getQuery(), ctx, Long.class));
@@ -240,8 +240,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -240,8 +240,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
240 @Override 240 @Override
241 public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) { 241 public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) {
242 return transactionTemplate.execute(status -> { 242 return transactionTemplate.execute(status -> {
243 - QueryContext ctx = new QueryContext();  
244 EntityType entityType = resolveEntityType(query.getEntityFilter()); 243 EntityType entityType = resolveEntityType(query.getEntityFilter());
  244 + QueryContext ctx = new QueryContext(new QuerySecurityContext(tenantId, customerId, entityType));
245 EntityDataPageLink pageLink = query.getPageLink(); 245 EntityDataPageLink pageLink = query.getPageLink();
246 246
247 List<EntityKeyMapping> mappings = EntityKeyMapping.prepareKeyMapping(query); 247 List<EntityKeyMapping> mappings = EntityKeyMapping.prepareKeyMapping(query);
@@ -264,9 +264,9 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -264,9 +264,9 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
264 .collect(Collectors.toList()); 264 .collect(Collectors.toList());
265 265
266 266
267 - String entityWhereClause = DefaultEntityQueryRepository.this.buildEntityWhere(ctx, tenantId, customerId, query.getEntityFilter(), entityFieldsFiltersMapping, entityType); 267 + String entityWhereClause = DefaultEntityQueryRepository.this.buildEntityWhere(ctx, query.getEntityFilter(), entityFieldsFiltersMapping);
268 String latestJoins = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings); 268 String latestJoins = EntityKeyMapping.buildLatestJoins(ctx, query.getEntityFilter(), entityType, allLatestMappings);
269 - String whereClause = DefaultEntityQueryRepository.this.buildWhere(ctx, latestFiltersMapping, query.getEntityFilter().getType(), entityType); 269 + String whereClause = DefaultEntityQueryRepository.this.buildWhere(ctx, latestFiltersMapping, query.getEntityFilter().getType());
270 String textSearchQuery = DefaultEntityQueryRepository.this.buildTextSearchQuery(ctx, selectionMapping, pageLink.getTextSearch()); 270 String textSearchQuery = DefaultEntityQueryRepository.this.buildTextSearchQuery(ctx, selectionMapping, pageLink.getTextSearch());
271 String entityFieldsSelection = EntityKeyMapping.buildSelections(entityFieldsSelectionMapping, query.getEntityFilter().getType(), entityType); 271 String entityFieldsSelection = EntityKeyMapping.buildSelections(entityFieldsSelectionMapping, query.getEntityFilter().getType(), entityType);
272 String entityTypeStr; 272 String entityTypeStr;
@@ -289,7 +289,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -289,7 +289,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
289 String fromClause = String.format("from (select %s from (select %s from %s e where %s) entities %s %s) result %s", 289 String fromClause = String.format("from (select %s from (select %s from %s e where %s) entities %s %s) result %s",
290 topSelection, 290 topSelection,
291 entityFieldsSelection, 291 entityFieldsSelection,
292 - addEntityTableQuery(ctx, query.getEntityFilter(), entityType), 292 + addEntityTableQuery(ctx, query.getEntityFilter()),
293 entityWhereClause, 293 entityWhereClause,
294 latestJoins, 294 latestJoins,
295 whereClause, 295 whereClause,
@@ -323,15 +323,10 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -323,15 +323,10 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
323 }); 323 });
324 } 324 }
325 325
326 - private String buildEntityWhere(QueryContext ctx,  
327 - TenantId tenantId,  
328 - CustomerId customerId,  
329 - EntityFilter entityFilter,  
330 - List<EntityKeyMapping> entityFieldsFilters,  
331 - EntityType entityType) {  
332 - String permissionQuery = this.buildPermissionQuery(ctx, entityFilter, tenantId, customerId, entityType); 326 + private String buildEntityWhere(QueryContext ctx, EntityFilter entityFilter, List<EntityKeyMapping> entityFieldsFilters) {
  327 + String permissionQuery = this.buildPermissionQuery(ctx, entityFilter);
333 String entityFilterQuery = this.buildEntityFilterQuery(ctx, entityFilter); 328 String entityFilterQuery = this.buildEntityFilterQuery(ctx, entityFilter);
334 - String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType(), entityType); 329 + String entityFieldsQuery = EntityKeyMapping.buildQuery(ctx, entityFieldsFilters, entityFilter.getType());
335 String result = permissionQuery; 330 String result = permissionQuery;
336 if (!entityFilterQuery.isEmpty()) { 331 if (!entityFilterQuery.isEmpty()) {
337 result += " and " + entityFilterQuery; 332 result += " and " + entityFilterQuery;
@@ -342,28 +337,28 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -342,28 +337,28 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
342 return result; 337 return result;
343 } 338 }
344 339
345 - private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter, TenantId tenantId, CustomerId customerId, EntityType entityType) { 340 + private String buildPermissionQuery(QueryContext ctx, EntityFilter entityFilter) {
346 switch (entityFilter.getType()) { 341 switch (entityFilter.getType()) {
347 case RELATIONS_QUERY: 342 case RELATIONS_QUERY:
348 case DEVICE_SEARCH_QUERY: 343 case DEVICE_SEARCH_QUERY:
349 case ASSET_SEARCH_QUERY: 344 case ASSET_SEARCH_QUERY:
350 case ENTITY_VIEW_SEARCH_QUERY: 345 case ENTITY_VIEW_SEARCH_QUERY:
351 - return this.defaultPermissionQuery(ctx, tenantId, customerId, entityType); 346 + return this.defaultPermissionQuery(ctx);
352 default: 347 default:
353 - if (entityType == EntityType.TENANT) {  
354 - ctx.addUuidParameter("permissions_tenant_id", tenantId.getId()); 348 + if (ctx.getEntityType() == EntityType.TENANT) {
  349 + ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId());
355 return "e.id=:permissions_tenant_id"; 350 return "e.id=:permissions_tenant_id";
356 } else { 351 } else {
357 - return this.defaultPermissionQuery(ctx, tenantId, customerId, entityType); 352 + return this.defaultPermissionQuery(ctx);
358 } 353 }
359 } 354 }
360 } 355 }
361 356
362 - private String defaultPermissionQuery(QueryContext ctx, TenantId tenantId, CustomerId customerId, EntityType entityType) {  
363 - ctx.addUuidParameter("permissions_tenant_id", tenantId.getId());  
364 - if (customerId != null && !customerId.isNullUid()) {  
365 - ctx.addUuidParameter("permissions_customer_id", customerId.getId());  
366 - if (entityType == EntityType.CUSTOMER) { 357 + private String defaultPermissionQuery(QueryContext ctx) {
  358 + ctx.addUuidParameter("permissions_tenant_id", ctx.getTenantId().getId());
  359 + if (ctx.getCustomerId() != null && !ctx.getCustomerId().isNullUid()) {
  360 + ctx.addUuidParameter("permissions_customer_id", ctx.getCustomerId().getId());
  361 + if (ctx.getEntityType() == EntityType.CUSTOMER) {
367 return "e.tenant_id=:permissions_tenant_id and e.id=:permissions_customer_id"; 362 return "e.tenant_id=:permissions_tenant_id and e.id=:permissions_customer_id";
368 } else { 363 } else {
369 return "e.tenant_id=:permissions_tenant_id and e.customer_id=:permissions_customer_id"; 364 return "e.tenant_id=:permissions_tenant_id and e.customer_id=:permissions_customer_id";
@@ -395,7 +390,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -395,7 +390,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
395 } 390 }
396 } 391 }
397 392
398 - private String addEntityTableQuery(QueryContext ctx, EntityFilter entityFilter, EntityType entityType) { 393 + private String addEntityTableQuery(QueryContext ctx, EntityFilter entityFilter) {
399 switch (entityFilter.getType()) { 394 switch (entityFilter.getType()) {
400 case RELATIONS_QUERY: 395 case RELATIONS_QUERY:
401 return relationQuery(ctx, (RelationsQueryFilter) entityFilter); 396 return relationQuery(ctx, (RelationsQueryFilter) entityFilter);
@@ -409,7 +404,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -409,7 +404,7 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
409 EntityViewSearchQueryFilter entityViewQuery = (EntityViewSearchQueryFilter) entityFilter; 404 EntityViewSearchQueryFilter entityViewQuery = (EntityViewSearchQueryFilter) entityFilter;
410 return entitySearchQuery(ctx, entityViewQuery, EntityType.ENTITY_VIEW, entityViewQuery.getEntityViewTypes()); 405 return entitySearchQuery(ctx, entityViewQuery, EntityType.ENTITY_VIEW, entityViewQuery.getEntityViewTypes());
411 default: 406 default:
412 - return entityTableMap.get(entityType); 407 + return entityTableMap.get(ctx.getEntityType());
413 } 408 }
414 } 409 }
415 410
@@ -505,8 +500,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { @@ -505,8 +500,8 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
505 return from; 500 return from;
506 } 501 }
507 502
508 - private String buildWhere(QueryContext ctx, List<EntityKeyMapping> latestFiltersMapping, EntityFilterType filterType, EntityType entityType) {  
509 - String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping, filterType, entityType); 503 + private String buildWhere(QueryContext ctx, List<EntityKeyMapping> latestFiltersMapping, EntityFilterType filterType) {
  504 + String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping, filterType);
510 if (!StringUtils.isEmpty(latestFilters)) { 505 if (!StringUtils.isEmpty(latestFilters)) {
511 return String.format("where %s", latestFilters); 506 return String.format("where %s", latestFilters);
512 } else { 507 } else {
@@ -214,11 +214,11 @@ public class EntityKeyMapping { @@ -214,11 +214,11 @@ public class EntityKeyMapping {
214 return alias; 214 return alias;
215 } 215 }
216 216
217 - public Stream<String> toQueries(QueryContext ctx, EntityFilterType filterType, EntityType entityType) { 217 + public Stream<String> toQueries(QueryContext ctx, EntityFilterType filterType) {
218 if (hasFilter()) { 218 if (hasFilter()) {
219 String keyAlias = entityKey.getType().equals(EntityKeyType.ENTITY_FIELD) ? "e" : alias; 219 String keyAlias = entityKey.getType().equals(EntityKeyType.ENTITY_FIELD) ? "e" : alias;
220 return keyFilters.stream().map(keyFilter -> 220 return keyFilters.stream().map(keyFilter ->
221 - this.buildKeyQuery(ctx, keyAlias, keyFilter, filterType, entityType)); 221 + this.buildKeyQuery(ctx, keyAlias, keyFilter, filterType));
222 } else { 222 } else {
223 return null; 223 return null;
224 } 224 }
@@ -271,8 +271,8 @@ public class EntityKeyMapping { @@ -271,8 +271,8 @@ public class EntityKeyMapping {
271 Collectors.joining(" ")); 271 Collectors.joining(" "));
272 } 272 }
273 273
274 - public static String buildQuery(QueryContext ctx, List<EntityKeyMapping> mappings, EntityFilterType filterType, EntityType entityType) {  
275 - return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx, filterType, entityType)).filter(Objects::nonNull).collect( 274 + public static String buildQuery(QueryContext ctx, List<EntityKeyMapping> mappings, EntityFilterType filterType) {
  275 + return mappings.stream().flatMap(mapping -> mapping.toQueries(ctx, filterType)).filter(Objects::nonNull).collect(
276 Collectors.joining(" AND ")); 276 Collectors.joining(" AND "));
277 } 277 }
278 278
@@ -385,33 +385,33 @@ public class EntityKeyMapping { @@ -385,33 +385,33 @@ public class EntityKeyMapping {
385 } 385 }
386 386
387 private String buildKeyQuery(QueryContext ctx, String alias, KeyFilter keyFilter, 387 private String buildKeyQuery(QueryContext ctx, String alias, KeyFilter keyFilter,
388 - EntityFilterType filterType, EntityType entityType) {  
389 - return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate(), filterType, entityType); 388 + EntityFilterType filterType) {
  389 + return this.buildPredicateQuery(ctx, alias, keyFilter.getKey(), keyFilter.getPredicate(), filterType);
390 } 390 }
391 391
392 private String buildPredicateQuery(QueryContext ctx, String alias, EntityKey key, 392 private String buildPredicateQuery(QueryContext ctx, String alias, EntityKey key,
393 - KeyFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) { 393 + KeyFilterPredicate predicate, EntityFilterType filterType) {
394 if (predicate.getType().equals(FilterPredicateType.COMPLEX)) { 394 if (predicate.getType().equals(FilterPredicateType.COMPLEX)) {
395 - return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate, filterType, entityType); 395 + return this.buildComplexPredicateQuery(ctx, alias, key, (ComplexFilterPredicate) predicate, filterType);
396 } else { 396 } else {
397 - return this.buildSimplePredicateQuery(ctx, alias, key, predicate, filterType, entityType); 397 + return this.buildSimplePredicateQuery(ctx, alias, key, predicate, filterType);
398 } 398 }
399 } 399 }
400 400
401 private String buildComplexPredicateQuery(QueryContext ctx, String alias, EntityKey key, 401 private String buildComplexPredicateQuery(QueryContext ctx, String alias, EntityKey key,
402 - ComplexFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) { 402 + ComplexFilterPredicate predicate, EntityFilterType filterType) {
403 return predicate.getPredicates().stream() 403 return predicate.getPredicates().stream()
404 - .map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate, filterType, entityType)) 404 + .map(keyFilterPredicate -> this.buildPredicateQuery(ctx, alias, key, keyFilterPredicate, filterType))
405 .filter(Objects::nonNull).collect(Collectors.joining( 405 .filter(Objects::nonNull).collect(Collectors.joining(
406 " " + predicate.getOperation().name() + " " 406 " " + predicate.getOperation().name() + " "
407 )); 407 ));
408 } 408 }
409 409
410 private String buildSimplePredicateQuery(QueryContext ctx, String alias, EntityKey key, 410 private String buildSimplePredicateQuery(QueryContext ctx, String alias, EntityKey key,
411 - KeyFilterPredicate predicate, EntityFilterType filterType, EntityType entityType) { 411 + KeyFilterPredicate predicate, EntityFilterType filterType) {
412 if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) { 412 if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) {
413 - Set<String> existingEntityFields = getExistingEntityFields(filterType, entityType);  
414 - String entityFieldAlias = getEntityFieldAlias(filterType, entityType); 413 + Set<String> existingEntityFields = getExistingEntityFields(filterType, ctx.getEntityType());
  414 + String entityFieldAlias = getEntityFieldAlias(filterType, ctx.getEntityType());
415 String column = null; 415 String column = null;
416 if (existingEntityFields.contains(entityFieldAlias)) { 416 if (existingEntityFields.contains(entityFieldAlias)) {
417 column = entityFieldColumnMap.get(entityFieldAlias); 417 column = entityFieldColumnMap.get(entityFieldAlias);
@@ -17,6 +17,9 @@ package org.thingsboard.server.dao.sql.query; @@ -17,6 +17,9 @@ package org.thingsboard.server.dao.sql.query;
17 17
18 import org.hibernate.type.PostgresUUIDType; 18 import org.hibernate.type.PostgresUUIDType;
19 import org.springframework.jdbc.core.namedparam.SqlParameterSource; 19 import org.springframework.jdbc.core.namedparam.SqlParameterSource;
  20 +import org.thingsboard.server.common.data.EntityType;
  21 +import org.thingsboard.server.common.data.id.CustomerId;
  22 +import org.thingsboard.server.common.data.id.TenantId;
20 23
21 import java.sql.Types; 24 import java.sql.Types;
22 import java.util.HashMap; 25 import java.util.HashMap;
@@ -27,10 +30,12 @@ import java.util.UUID; @@ -27,10 +30,12 @@ import java.util.UUID;
27 public class QueryContext implements SqlParameterSource { 30 public class QueryContext implements SqlParameterSource {
28 private static final PostgresUUIDType UUID_TYPE = new PostgresUUIDType(); 31 private static final PostgresUUIDType UUID_TYPE = new PostgresUUIDType();
29 32
  33 + private final QuerySecurityContext securityCtx;
30 private final StringBuilder query; 34 private final StringBuilder query;
31 private final Map<String, Parameter> params; 35 private final Map<String, Parameter> params;
32 36
33 - public QueryContext() { 37 + public QueryContext(QuerySecurityContext securityCtx) {
  38 + this.securityCtx = securityCtx;
34 query = new StringBuilder(); 39 query = new StringBuilder();
35 params = new HashMap<>(); 40 params = new HashMap<>();
36 } 41 }
@@ -123,4 +128,16 @@ public class QueryContext implements SqlParameterSource { @@ -123,4 +128,16 @@ public class QueryContext implements SqlParameterSource {
123 this.name = name; 128 this.name = name;
124 } 129 }
125 } 130 }
  131 +
  132 + public TenantId getTenantId() {
  133 + return securityCtx.getTenantId();
  134 + }
  135 +
  136 + public CustomerId getCustomerId() {
  137 + return securityCtx.getCustomerId();
  138 + }
  139 +
  140 + public EntityType getEntityType() {
  141 + return securityCtx.getEntityType();
  142 + }
126 } 143 }
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.sql.query;
  17 +
  18 +import lombok.AllArgsConstructor;
  19 +import lombok.Getter;
  20 +import org.hibernate.type.PostgresUUIDType;
  21 +import org.springframework.jdbc.core.namedparam.SqlParameterSource;
  22 +import org.thingsboard.server.common.data.EntityType;
  23 +import org.thingsboard.server.common.data.id.CustomerId;
  24 +import org.thingsboard.server.common.data.id.TenantId;
  25 +
  26 +import java.sql.Types;
  27 +import java.util.HashMap;
  28 +import java.util.List;
  29 +import java.util.Map;
  30 +import java.util.UUID;
  31 +
  32 +@AllArgsConstructor
  33 +public class QuerySecurityContext {
  34 +
  35 + @Getter
  36 + private final TenantId tenantId;
  37 + @Getter
  38 + private final CustomerId customerId;
  39 + @Getter
  40 + private final EntityType entityType;
  41 +
  42 +}