From 5d1da280916375725b129d1e772a6128db3e31c6 Mon Sep 17 00:00:00 2001 From: Victor Alfaro Date: Tue, 7 Jan 2025 22:26:00 -0600 Subject: [PATCH] #31019: Using JWT 'expiresIn' field to determine if token is expired and adding fallback to dotCMS 'ANALYTICS_ACCESSTOKEN_TTL' config value, removing 'Bearer' prefix from Authorization header since CubeJS does not like it and finally setting 'CUBEJS_JWT_ISSUER' env-var at analytics infrastructure docker-compose to 'http://host.docker.internal:61111/realms/dotcms' since most of the times this is run inside a Dcoker container --- .../analytics/docker-compose.yml | 2 +- .../analytics/setup/config/dev/cube/cube.js | 15 +++--------- .../analytics/helper/AnalyticsHelper.java | 23 +++++++++++++++---- .../java/com/dotcms/cube/CubeJSClient.java | 7 ++---- 4 files changed, 25 insertions(+), 22 deletions(-) diff --git a/docker/docker-compose-examples/analytics/docker-compose.yml b/docker/docker-compose-examples/analytics/docker-compose.yml index 69a5e35e0f74..01ac28c8b880 100644 --- a/docker/docker-compose-examples/analytics/docker-compose.yml +++ b/docker/docker-compose-examples/analytics/docker-compose.yml @@ -124,7 +124,7 @@ services: - CUBEJS_DB_PASS=${CH_PWD:-clickhouse_password} - CUBEJS_JWK_URL=${JWKS_URL:-http://host.docker.internal:61111/realms/dotcms/protocol/openid-connect/certs} - CUBEJS_JWT_AUDIENCE=api-dotcms-analytics-audience - - CUBEJS_JWT_ISSUER=${AUTH_SERVER_URL:-http://localhost:61111/realms/dotcms} + - CUBEJS_JWT_ISSUER=${AUTH_SERVER_URL:-http://host.docker.internal:61111/realms/dotcms} - CUBEJS_JWT_ALGS=RS256 - CUBEJS_JWT_CLAIMS_NAMESPACE=https://dotcms.com/analytics - CUBEJS_LOG_LEVEL=debug diff --git a/docker/docker-compose-examples/analytics/setup/config/dev/cube/cube.js b/docker/docker-compose-examples/analytics/setup/config/dev/cube/cube.js index ab2d68f32518..c11b425f998b 100644 --- a/docker/docker-compose-examples/analytics/setup/config/dev/cube/cube.js +++ b/docker/docker-compose-examples/analytics/setup/config/dev/cube/cube.js @@ -1,14 +1,9 @@ - - // cube.js configuration file module.exports = { - /* - contextToAppId: ({ securityContext }) => + /*contextToAppId: ({ securityContext }) => `CUBEJS_APP_${securityContext.customerId}`, preAggregationsSchema: ({ securityContext }) => - `pre_aggregations_${securityContext.customerId}`, -*/ - + `pre_aggregations_${securityContext.customerId}`,*/ queryRewrite: (query, { securityContext }) => { @@ -17,7 +12,6 @@ module.exports = { } const tokenData = securityContext["https://dotcms.com/analytics"]; - const isRequestQuery = (query.measures + query.dimensions).includes("request."); if (isRequestQuery) { @@ -26,7 +20,6 @@ module.exports = { operator: 'equals', values: [tokenData.clusterId], }); - query.filters.push({ member: 'request.customerId', operator: 'equals', @@ -34,9 +27,7 @@ module.exports = { }); } - return query; }, - -}; \ No newline at end of file +}; diff --git a/dotCMS/src/main/java/com/dotcms/analytics/helper/AnalyticsHelper.java b/dotCMS/src/main/java/com/dotcms/analytics/helper/AnalyticsHelper.java index 361938d1408d..897f8841e006 100644 --- a/dotCMS/src/main/java/com/dotcms/analytics/helper/AnalyticsHelper.java +++ b/dotCMS/src/main/java/com/dotcms/analytics/helper/AnalyticsHelper.java @@ -93,11 +93,13 @@ public Optional extractAnalyticsKey(final CircuitBreakerUrl.Respon * @return true if current time is in the TTL window */ private boolean filterIssueDate(final AccessToken accessToken, final BiPredicate filter) { + final long tokenTtl = Optional.ofNullable(accessToken.expiresIn().longValue()).orElse(accessTokenTtl.get()); return Optional.ofNullable(accessToken.issueDate()) .map(issuedAt -> { final Instant now = Instant.now(); - final Instant expireDate = issuedAt.plusSeconds(accessTokenTtl.get()); - return now.isBefore(expireDate) && (filter == null || filter.test(now, expireDate)); + final Instant expireDate = issuedAt.plusSeconds(tokenTtl); + return now.isBefore(expireDate) && + Optional.ofNullable(filter).map(f -> f.test(now, expireDate)).orElse (true); }) .orElseGet(() -> { Logger.warn(AnalyticsHelper.class, "ACCESS_TOKEN does not have a issued date, filtering token out"); @@ -224,12 +226,25 @@ private boolean canUseToken(final TokenStatus tokenStatus) { * when add in the corresponding header. * * @param accessToken provided access token + * @param type token type (most of times it will be 'Bearer') * @return the actual string value of token for header usage * @throws AnalyticsException when validating token */ - public String formatBearer(final AccessToken accessToken) throws AnalyticsException { + public String formatToken(final AccessToken accessToken, final String type) throws AnalyticsException { checkAccessToken(accessToken); - return JsonWebTokenAuthCredentialProcessor.BEARER + accessToken.accessToken(); + return StringUtils.defaultIfBlank(type, StringPool.BLANK) + accessToken.accessToken(); + } + + /** + * Extracts actual access token value from {@link AccessToken} and prepends the "Bearer " prefix to be used + * when add in the corresponding header. + * + * @param accessToken provided access token + * @return the actual string value of token for header usage + * @throws AnalyticsException when validating token + */ + public String formatBearer(final AccessToken accessToken) throws AnalyticsException { + return formatToken(accessToken, JsonWebTokenAuthCredentialProcessor.BEARER); } /** diff --git a/dotCMS/src/main/java/com/dotcms/cube/CubeJSClient.java b/dotCMS/src/main/java/com/dotcms/cube/CubeJSClient.java index 6a1d168fa085..3b1910a5ba8f 100644 --- a/dotCMS/src/main/java/com/dotcms/cube/CubeJSClient.java +++ b/dotCMS/src/main/java/com/dotcms/cube/CubeJSClient.java @@ -7,7 +7,6 @@ import com.dotcms.http.CircuitBreakerUrl.Method; import com.dotcms.http.CircuitBreakerUrl.Response; import com.dotcms.metrics.timing.TimeMetric; -import com.dotcms.util.CollectionsUtils; import com.dotcms.util.DotPreconditions; import com.dotcms.util.JsonUtil; import com.dotmarketing.util.Logger; @@ -22,7 +21,7 @@ import java.util.Map; /** - * CubeJS Client it allow to send a Request to a Cube JS Server. + * CubeJS Client it allows to send a Request to a Cube JS Server. * Example: * * @@ -40,7 +39,6 @@ */ public class CubeJSClient { - private int PAGE_SIZE = 1000; private final String url; private final AccessToken accessToken; @@ -148,9 +146,8 @@ private Response getStringResponse(final CircuitBreakerUrl cubeJSClient, */ private Map cubeJsHeaders(final AccessToken accessToken) throws AnalyticsException { return ImmutableMap.builder() - .put(HttpHeaders.AUTHORIZATION, AnalyticsHelper.get().formatBearer(accessToken)) + .put(HttpHeaders.AUTHORIZATION, AnalyticsHelper.get().formatToken(accessToken, null)) .build(); } - }