From dab2a5ded7e0ffcebb8abf8cb5f76bba74eba529 Mon Sep 17 00:00:00 2001 From: navodzoysa Date: Tue, 20 Dec 2022 12:26:14 +0530 Subject: [PATCH] Check tenant IDs of cached queries before sending to Grafana --- .../service/impl/GrafanaQueryServiceImpl.java | 19 ++++++- .../query/GrafanaPreparedQueryBuilder.java | 56 ++++++++++++++++++- .../proxy/core/util/GrafanaConstants.java | 1 + 3 files changed, 73 insertions(+), 3 deletions(-) diff --git a/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/service/impl/GrafanaQueryServiceImpl.java b/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/service/impl/GrafanaQueryServiceImpl.java index b15ebed76a..7af9acf559 100644 --- a/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/service/impl/GrafanaQueryServiceImpl.java +++ b/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/service/impl/GrafanaQueryServiceImpl.java @@ -68,8 +68,23 @@ public class GrafanaQueryServiceImpl implements GrafanaQueryService { int datasourceId = datasourceIdJson.getAsInt(); CacheManager cacheManager = CacheManager.getInstance(); String encodedQuery = cacheManager.getEncodedQueryCache().getIfPresent(rawSql); - if (cacheManager.getEncodedQueryCache().getIfPresent(rawSql) != null) { - queryObj.addProperty(GrafanaConstants.RAW_SQL_KEY, encodedQuery); + if (encodedQuery != null && !encodedQuery.isEmpty()) { + // Checks if the tenant ID in the cached query (encodedQuery) is matching the current tenant ID + // taken from Carbon Context and if it's not matching then the query is modified with the current + // tenant ID and then added to the cache + if (encodedQuery.contains(GrafanaConstants.ENCODED_QUERY_TENANT_ID_KEY)) { + String encodedQueryTenantId = GrafanaPreparedQueryBuilder.getEncodedQueryTenantId(encodedQuery); + boolean isMatchingTenantId = GrafanaPreparedQueryBuilder.isMatchingTenantId(encodedQueryTenantId); + if (isMatchingTenantId) { + queryObj.addProperty(GrafanaConstants.RAW_SQL_KEY, encodedQuery); + } else { + String modifiedEncodedQuery = GrafanaPreparedQueryBuilder.modifyEncodedQuery(encodedQuery); + CacheManager.getInstance().getEncodedQueryCache().put(rawSql, modifiedEncodedQuery); + queryObj.addProperty(GrafanaConstants.RAW_SQL_KEY, modifiedEncodedQuery); + } + } else { + queryObj.addProperty(GrafanaConstants.RAW_SQL_KEY, encodedQuery); + } return; } Datasource datasource = cacheManager.getDatasourceAPICache().getIfPresent(datasourceId); diff --git a/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/sql/query/GrafanaPreparedQueryBuilder.java b/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/sql/query/GrafanaPreparedQueryBuilder.java index 8b8606dacb..da14278caf 100644 --- a/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/sql/query/GrafanaPreparedQueryBuilder.java +++ b/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/sql/query/GrafanaPreparedQueryBuilder.java @@ -38,6 +38,7 @@ public class GrafanaPreparedQueryBuilder { private static final String VAR_PARAM_TEMPLATE = "$param"; private static final String GRAFANA_QUOTED_VAR_REGEX = "('\\$(\\d|\\w|_)+')|('\\$\\{.*?\\}')|(\"\\$(\\d|\\w|_)+\")|(\"\\$\\{.*?\\}\")"; private static final String GRAFANA_VAR_REGEX = "(\\$(\\d|\\w|_)+)|(\\$\\{.*?\\})"; + private static final String ENCODED_QUERY_TENANT_ID_REGEX = "TENANT_ID\\s=\\s('[^']+'|-?[1-9]\\d*|0)"; public static PreparedQuery build(String queryTemplate, String rawQuery) throws QueryMisMatch { @@ -125,6 +126,60 @@ public class GrafanaPreparedQueryBuilder { return new PreparedQuery(preparedQueryBuilder.toString(), parameters); } + /** + * Get the tenant ID used in the cached query with the matching regex pattern which are integers that + * may or may not have surrounding single quotes and could have a minus sign (e.g., '-1234') + * @param encodedQuery the cached query + * @return returns the tenant ID extracted from the cached query + */ + public static String getEncodedQueryTenantId(String encodedQuery) { + Pattern pattern = Pattern.compile(ENCODED_QUERY_TENANT_ID_REGEX); + Matcher matcher = pattern.matcher(encodedQuery); + String encodedQueryTenantId = ""; + while (matcher.find()) { + encodedQueryTenantId = matcher.group(1); + if (encodedQueryTenantId != null && !encodedQueryTenantId.isEmpty()) { + break; + } + } + return unQuoteString(encodedQueryTenantId); + } + + /** + * Checks if passed tenant ID is matching with tenant ID from Carbon Context + * @param encodedQueryTenantId the tenant ID + * @return true if tenant IDs match otherwise false + */ + public static boolean isMatchingTenantId(String encodedQueryTenantId) { + if (encodedQueryTenantId != null && !encodedQueryTenantId.isEmpty()) { + return GrafanaUtil.getTenantId() == Integer.parseInt(encodedQueryTenantId); + } + return false; + } + + /** + * Modify the tenant ID used in the cached query to the current tenant ID taken from Carbon Context + * with the matching regex pattern which are integers that may or may not have surrounding single quotes and + * could have a minus sign (e.g., '-1234') + * @param encodedQuery the cached query + * @return returns the modified query with the current tenant ID + */ + public static String modifyEncodedQuery(String encodedQuery) { + Pattern pattern = Pattern.compile(ENCODED_QUERY_TENANT_ID_REGEX); + Matcher matcher = pattern.matcher(encodedQuery); + StringBuffer stringBuffer = new StringBuffer(encodedQuery.length()); + String encodedQueryTenantId = ""; + while (matcher.find()) { + encodedQueryTenantId = matcher.group(1); + if (encodedQueryTenantId != null && !encodedQueryTenantId.isEmpty()) { + matcher.appendReplacement(stringBuffer, Matcher.quoteReplacement( + GrafanaConstants.ENCODED_QUERY_TENANT_ID_KEY + " " + GrafanaUtil.getTenantId())); + } + } + matcher.appendTail(stringBuffer); + return stringBuffer.toString(); + } + private static String[] splitByComma(String str) { // Using regex to avoid splitting by comma inside quotes return str.split("(\\s|\\t)*,(\\s|\\t)*(?=(?:[^'\"]*['|\"][^'\"]*['|\"])*[^'\"]*$)"); @@ -194,5 +249,4 @@ public class GrafanaPreparedQueryBuilder { private static String singleQuoteString(String str) { return "'" + str + "'"; } - } diff --git a/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/util/GrafanaConstants.java b/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/util/GrafanaConstants.java index b8a33f8b32..0abed858b7 100644 --- a/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/util/GrafanaConstants.java +++ b/components/analytics-mgt/grafana-mgt/io.entgra.analytics.mgt.grafana.proxy.core/src/main/java/io/entgra/analytics/mgt/grafana/proxy/core/util/GrafanaConstants.java @@ -39,6 +39,7 @@ public class GrafanaConstants { public static final int IFRAME_URL_DASHBOARD_UID_INDEX = 1; public static final String TENANT_ID_VAR_NAME = "tenantId"; + public static final String ENCODED_QUERY_TENANT_ID_KEY = "TENANT_ID ="; public static final String VAR_PREFIX = "$"; public static final String TENANT_ID_VAR = VAR_PREFIX + TENANT_ID_VAR_NAME; public static final String QUERY_PARAM_VAR_PREFIX = "var-";