Skip to content

Commit

Permalink
#31019: Using JWT 'expiresIn' field to determine if token is expired …
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
victoralfaro-dotcms committed Jan 8, 2025
1 parent c8c971b commit 5d1da28
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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 }) => {

Expand All @@ -17,7 +12,6 @@ module.exports = {
}

const tokenData = securityContext["https://dotcms.com/analytics"];

const isRequestQuery = (query.measures + query.dimensions).includes("request.");

if (isRequestQuery) {
Expand All @@ -26,17 +20,14 @@ module.exports = {
operator: 'equals',
values: [tokenData.clusterId],
});

query.filters.push({
member: 'request.customerId',
operator: 'equals',
values: [tokenData.customerId],
});
}


return query;
},


};
};
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,13 @@ public Optional<AnalyticsKey> extractAnalyticsKey(final CircuitBreakerUrl.Respon
* @return true if current time is in the TTL window
*/
private boolean filterIssueDate(final AccessToken accessToken, final BiPredicate<Instant, Instant> 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");
Expand Down Expand Up @@ -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);
}

/**
Expand Down
7 changes: 2 additions & 5 deletions dotCMS/src/main/java/com/dotcms/cube/CubeJSClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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:
*
* <code>
Expand All @@ -40,7 +39,6 @@
*/
public class CubeJSClient {

private int PAGE_SIZE = 1000;
private final String url;
private final AccessToken accessToken;

Expand Down Expand Up @@ -148,9 +146,8 @@ private Response<String> getStringResponse(final CircuitBreakerUrl cubeJSClient,
*/
private Map<String, String> cubeJsHeaders(final AccessToken accessToken) throws AnalyticsException {
return ImmutableMap.<String, String>builder()
.put(HttpHeaders.AUTHORIZATION, AnalyticsHelper.get().formatBearer(accessToken))
.put(HttpHeaders.AUTHORIZATION, AnalyticsHelper.get().formatToken(accessToken, null))
.build();
}


}

0 comments on commit 5d1da28

Please sign in to comment.