Skip to content

Commit

Permalink
Harmony 1950 - X-Request-Id header (#663)
Browse files Browse the repository at this point in the history
* HARMONY-1950: Add X-Request-Id header to CMR queries

* HARMONY-1950: Add context to more cmr function calls to match changes
to API

* HARMONY-1950: Add 'X-Request-Id' header to EDL requests for tracking

* HARMONY-1950: Fix typo in comment
  • Loading branch information
indiejames authored Nov 25, 2024
1 parent 282b0a1 commit 0bab4dd
Show file tree
Hide file tree
Showing 19 changed files with 196 additions and 116 deletions.
2 changes: 1 addition & 1 deletion scripts/service-comparison.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ async function runComparisons(environments = allEnvironments): Promise<void> {
const harmonyServiceConfigs = loadServiceConfigs(environment)
.filter((config) => config.umm_s); // Ignore any service definitions that do not point to a UMM-S record
const ummConceptIds = harmonyServiceConfigs.map((config) => config.umm_s);
const ummRecords = await getServicesByIds(ummConceptIds, null);
const ummRecords = await getServicesByIds({ id: 'harmony-service-comparison-script' }, ummConceptIds, null);
const ummRecordsMap = createUmmRecordsMap(ummRecords);
for (const harmonyConfig of harmonyServiceConfigs) {
const ummRecord = ummRecordsMap[harmonyConfig.umm_s];
Expand Down
6 changes: 3 additions & 3 deletions services/harmony/app/frontends/capabilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ async function loadCollectionInfo(req: HarmonyRequest): Promise<CmrCollection> {
} else if (collectionid && shortname) {
throw new RequestValidationError('Must specify only one of collectionId or shortName, not both');
} else if (collectionid) {
collections = await getCollectionsByIds([collectionid], req.accessToken);
collections = await getCollectionsByIds(req.context, [collectionid], req.accessToken);
if (collections.length === 0) {
const message = `${collectionid} must be a CMR collection identifier, but `
+ 'we could not find a matching collection. Please make sure the collection ID '
Expand All @@ -82,7 +82,7 @@ async function loadCollectionInfo(req: HarmonyRequest): Promise<CmrCollection> {
}
pickedCollection = collections[0];
} else {
collections = await getCollectionsByShortName(shortname, req.accessToken);
collections = await getCollectionsByShortName(req.context, shortname, req.accessToken);
if (collections.length === 0) {
const message = `Unable to find collection short name ${shortname} in the CMR. Please `
+ ' make sure the short name is correct and that you have access to the collection.';
Expand All @@ -96,7 +96,7 @@ async function loadCollectionInfo(req: HarmonyRequest): Promise<CmrCollection> {
pickedCollection = harmonyCollection || pickedCollection;
}
}
pickedCollection.variables = await getVariablesForCollection(pickedCollection, req.accessToken);
pickedCollection.variables = await getVariablesForCollection(req.context, pickedCollection, req.accessToken);
return pickedCollection;
}

Expand Down
2 changes: 1 addition & 1 deletion services/harmony/app/frontends/service-image-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ async function validateUserIsInDeployerOrCoreGroup(
req: HarmonyRequest, res: Response,
): Promise<boolean> {
const { hasCorePermissions, isServiceDeployer } = await getEdlGroupInformation(
req.user, req.context.logger,
req.context, req.user,
);

if (!isServiceDeployer && !hasCorePermissions) {
Expand Down
6 changes: 3 additions & 3 deletions services/harmony/app/frontends/workflow-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -551,7 +551,7 @@ export async function getWorkItemsTable(
try {
const isAdminRoute = req.context.isAdminAccess;
const { isAdmin, isLogViewer } = await getEdlGroupInformation(
req.user, req.context.logger,
req.context, req.user,
);
const isAdminOrLogViewer = isAdmin || isLogViewer;
const job = await getJobIfAllowed(jobID, req.user, isAdmin, req.accessToken, true);
Expand Down Expand Up @@ -617,7 +617,7 @@ export async function getWorkItemTableRow(
const { jobID, id } = req.params;
try {
const { isAdmin, isLogViewer } = await getEdlGroupInformation(
req.user, req.context.logger,
req.context, req.user,
);
const isAdminOrLogViewer = isAdmin || isLogViewer;
const job = await getJobIfAllowed(jobID, req.user, isAdmin, req.accessToken, true);
Expand Down Expand Up @@ -727,7 +727,7 @@ export async function getWorkItemLogs(
const { id, jobID } = req.params;
try {
const { isAdmin, isLogViewer } = await getEdlGroupInformation(
req.user, req.context.logger,
req.context, req.user,
);
const isAdminOrLogViewer = isAdmin || isLogViewer;
if (!isAdminOrLogViewer) {
Expand Down
16 changes: 9 additions & 7 deletions services/harmony/app/middleware/cmr-collection-reader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ForbiddenError, NotFoundError, ServerError } from '../util/errors';
import HarmonyRequest from '../models/harmony-request';
import { listToText } from '@harmony/util/string';
import { EdlUserEulaInfo, verifyUserEula } from '../util/edl-api';
import RequestContext from '../models/request-context';

// CMR Collection IDs separated by delimiters of single "+" or single whitespace
// (some clients may translate + to space)
Expand All @@ -20,13 +21,14 @@ const EDR_COLLECTION_ROUTE_REGEX = /^\/ogc-api-edr\/.*\/collections\/(.*)\//;
* Loads the variables for the given collection from the CMR and sets the collection's
* "variables" attribute to the result
*
* @param context - The context for the user's request
* @param collection - The collection whose variables should be loaded
* @param token - Access token for user request
* @returns Resolves when the loading completes
*/
async function loadVariablesForCollection(collection: CmrCollection, token: string): Promise<void> {
async function loadVariablesForCollection(context: RequestContext, collection: CmrCollection, token: string): Promise<void> {
const c = collection; // We are mutating collection
c.variables = await getVariablesForCollection(collection, token);
c.variables = await getVariablesForCollection(context, collection, token);
}

/**
Expand All @@ -41,7 +43,7 @@ async function verifyEulaAcceptance(collections: CmrCollection[], req: HarmonyRe
for (const collection of collections) {
if (collection.eula_identifiers) {
for (const eulaId of collection.eula_identifiers) {
const eulaInfo: EdlUserEulaInfo = await verifyUserEula(req.user, eulaId, req.context.logger);
const eulaInfo: EdlUserEulaInfo = await verifyUserEula(req.context, req.user, eulaId);
if (eulaInfo.statusCode == 404 && eulaInfo.acceptEulaUrl) { // EULA wasn't accepted
acceptEulaUrls.push(eulaInfo.acceptEulaUrl);
} else if (eulaInfo.statusCode == 404) {
Expand Down Expand Up @@ -96,7 +98,7 @@ async function cmrCollectionReader(req: HarmonyRequest, res, next: NextFunction)
req.collectionIds = collectionIds;
req.context.logger.info(`Matched CMR concept IDs: ${collectionIds}`);

req.collections = await getCollectionsByIds(collectionIds, req.accessToken);
req.collections = await getCollectionsByIds(req.context, collectionIds, req.accessToken);
const { collections } = req;

await verifyEulaAcceptance(collections, req);
Expand All @@ -118,7 +120,7 @@ async function cmrCollectionReader(req: HarmonyRequest, res, next: NextFunction)

const promises = [];
for (const collection of collections) {
promises.push(loadVariablesForCollection(collection, req.accessToken));
promises.push(loadVariablesForCollection(req.context, collection, req.accessToken));
}
await Promise.all(promises);
} else {
Expand All @@ -133,7 +135,7 @@ async function cmrCollectionReader(req: HarmonyRequest, res, next: NextFunction)
shortName = shortNameMatch[2].substr(1, shortNameMatch[2].length - 2);
}

const collections = await getCollectionsByShortName(shortName, req.accessToken);
const collections = await getCollectionsByShortName(req.context, shortName, req.accessToken);
let pickedCollection = collections[0];
if (collections.length > 1) {
// If there are multiple collections matching prefer a collection that is configured
Expand All @@ -146,7 +148,7 @@ async function cmrCollectionReader(req: HarmonyRequest, res, next: NextFunction)

req.collections = [pickedCollection];
req.collectionIds = [pickedCollection.id];
await loadVariablesForCollection(pickedCollection, req.accessToken);
await loadVariablesForCollection(req.context, pickedCollection, req.accessToken);
if (collections.length > 1) {
const collectionLandingPage = `${cmrApiConfig.baseURL}/concepts/${pickedCollection.id}`;
req.context.messages.push(`There were ${collections.length} collections that matched the`
Expand Down
2 changes: 2 additions & 0 deletions services/harmony/app/middleware/cmr-granule-locator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ async function cmrGranuleLocatorTurbo(
if ( req.context.serviceConfig.steps[0].image.match('harmonyservices/query-cmr:.*') ) {
cmrQuery.collection_concept_id = source.collection;
const { hits, sessionKey } = await queryGranulesWithSearchAfter(
req.context,
req.accessToken,
maxGranules,
cmrQuery,
Expand Down Expand Up @@ -280,6 +281,7 @@ async function cmrGranuleLocatorNonTurbo(
cmrQuery.geojson = operation.geojson;
}
cmrResponse = await queryGranulesForCollection(
req.context,
source.collection,
cmrQuery,
req.accessToken,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ async function cmrUmmCollectionReader(req: HarmonyRequest, res, next: NextFuncti
try {
const hasUmmConditional = req.context.serviceConfig?.steps?.filter((s) => s.conditional?.umm_c);
if (hasUmmConditional && hasUmmConditional.length > 0) {
req.operation.ummCollections = await getUmmCollectionsByIds(req.collectionIds, req.accessToken);
req.operation.ummCollections = await getUmmCollectionsByIds(req.context, req.collectionIds, req.accessToken);
}
next();
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ export default function buildEdlAuthorizer(paths: Array<string | RegExp> = []):
if (authHeader) {
const match = authHeader.match(BEARER_TOKEN_REGEX);
if (match) {
const { logger } = req.context;
const userToken = match[1];
try {
// Get the username for the provided token from EDL
const username = await getUserIdRequest(userToken, logger);
const username = await getUserIdRequest(req.context, userToken);
req.user = username;
req.accessToken = userToken;
req.authorized = true;
Expand Down
4 changes: 2 additions & 2 deletions services/harmony/app/middleware/permission-groups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export async function admin(
req: HarmonyRequest, res: Response, next: NextFunction,
): Promise<void> {
try {
const { isAdmin } = await getEdlGroupInformation(req.user, req.context.logger);
const { isAdmin } = await getEdlGroupInformation(req.context, req.user);
if (isAdmin) {
req.context.isAdminAccess = true;
next();
Expand All @@ -43,7 +43,7 @@ export async function core(
req: HarmonyRequest, res: Response, next: NextFunction,
): Promise<void> {
try {
const { hasCorePermissions } = await getEdlGroupInformation(req.user, req.context.logger);
const { hasCorePermissions } = await getEdlGroupInformation(req.context, req.user);
if (hasCorePermissions) {
req.context.isCoreAccess = true;
next();
Expand Down
3 changes: 2 additions & 1 deletion services/harmony/app/models/job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@ export class Job extends DBRecord implements JobRecord {
*/
async collectionsHaveEulaRestriction(accessToken: string): Promise<boolean> {
const cmrCollections = await getCollectionsByIds(
{ 'id': this.requestId },
this.collectionIds,
accessToken,
CmrTagKeys.HasEula,
Expand All @@ -1007,7 +1008,7 @@ export class Job extends DBRecord implements JobRecord {
* @returns true or false
*/
async collectionsHaveGuestReadRestriction(accessToken: string): Promise<boolean> {
const permissionsMap: CmrPermissionsMap = await getPermissions(this.collectionIds, accessToken);
const permissionsMap: CmrPermissionsMap = await getPermissions({ 'id': this.requestId }, this.collectionIds, accessToken);
return this.collectionIds.some((collectionId) => (
!permissionsMap[collectionId]
|| !(permissionsMap[collectionId].indexOf(CmrPermission.Read) > -1)));
Expand Down
Loading

0 comments on commit 0bab4dd

Please sign in to comment.