Skip to content

Commit

Permalink
HARMONY-1834: Support cookie-secret header when getting service-deplo…
Browse files Browse the repository at this point in the history
…yments-state.
  • Loading branch information
ygliuvt committed Aug 12, 2024
1 parent cdb679d commit 09db999
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 16 deletions.
2 changes: 1 addition & 1 deletion docs/guides/develop.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Highly Recommended:

Optional:
* [awscli-local](https://github.com/localstack/awscli-local) - CLI helpers for interacting with localstack
* [Python](https://www.python.org) version 3.7 - Useful for locally running and testing harmony-docker and other backend services
* [Python](https://www.python.org) version 3.11 - Useful for locally running and testing harmony-docker and other backend services

## Set up Environment

Expand Down
4 changes: 3 additions & 1 deletion services/harmony/app/frontends/service-image-tags.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Response, NextFunction } from 'express';
import HarmonyRequest from '../models/harmony-request';
import { ECR } from '../util/container-registry';
import { hasCookieSecret } from '../util/cookie-secret';
import { getEdlGroupInformation, validateUserIsInCoreGroup } from '../util/edl-api';
import { exec } from 'child_process';
import * as path from 'path';
Expand Down Expand Up @@ -521,7 +522,8 @@ export async function updateServiceImageTag(
export async function getServiceImageTagState(
req: HarmonyRequest, res: Response, _next: NextFunction,
): Promise<void> {
if (! await validateUserIsInDeployerOrCoreGroup(req, res)) return;
if (!hasCookieSecret(req))
if (! await validateUserIsInDeployerOrCoreGroup(req, res)) return;

const { enabled, message } = await getEnabledAndMessage();
res.statusCode = 200;
Expand Down
2 changes: 1 addition & 1 deletion services/harmony/app/routers/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ const authorizedRoutes = [
'/service-results/*',
'/workflow-ui*',
'/service-image*',
'/service-deployment*',
'/service-deployment\//*',
'/ogc-api-edr/.*/collections/*',
];

Expand Down
16 changes: 16 additions & 0 deletions services/harmony/app/util/cookie-secret.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import HarmonyRequest from '../models/harmony-request';

/**
* Validate that the request has correct cookie secret in header
* @param req - The request object
* @returns Boolean `true` if the request has correct cookie secret in header, `false` otherwise
*/
export function hasCookieSecret(req: HarmonyRequest): boolean {
const headerSecret = req.headers['cookie-secret'];
const secret = process.env.COOKIE_SECRET;
if (headerSecret === secret) {
return true;
}

return false;
}
24 changes: 11 additions & 13 deletions services/harmony/app/util/edl-api.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as axios from 'axios';
import { hasCookieSecret } from './cookie-secret';
import { ForbiddenError } from './errors';
import { Response } from 'express';
import { Logger } from 'winston';
Expand Down Expand Up @@ -187,20 +188,17 @@ export async function validateUserIsInCoreGroup(
req: HarmonyRequest, res: Response,
): Promise<boolean> {
// if request has cookie-secret header, it is in the core permissions group
const headerSecret = req.headers['cookie-secret'];
const secret = process.env.COOKIE_SECRET;
if (headerSecret === secret) {
return true;
}

const { hasCorePermissions } = await getEdlGroupInformation(
req.user, req.context.logger,
);
if (! hasCookieSecret(req)) {
const { hasCorePermissions } = await getEdlGroupInformation(
req.user, req.context.logger,
);

if (!hasCorePermissions) {
res.statusCode = 403;
res.send(`User ${req.user} does not have permission to access this resource`);
return false;
if (!hasCorePermissions) {
res.statusCode = 403;
res.send(`User ${req.user} does not have permission to access this resource`);
return false;
}
}

return true;
}
48 changes: 48 additions & 0 deletions services/harmony/test/service-image-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1397,6 +1397,54 @@ describe('Service self-deployment failure', async function () {
});
});

describe('get service deployments state with cookie-secret', async function () {
beforeEach(function () {
process.env.COOKIE_SECRET = 'cookie-secret-value';
});

hookServersStartStop({ skipEarthdataLogin: true });

describe('when incorrect cookie-secret header is provided', async function () {
before(async function () {
this.res = await request(this.frontend)
.get('/service-deployments-state')
.set('cookie-secret', 'wrong_secret');
});

after(function () {
delete this.res;
});

it('rejects the request', async function () {
expect(this.res.status).to.equal(403);
});

it('returns a meaningful error message', async function () {
expect(this.res.text).to.equal('User undefined does not have permission to access this resource');
});
});

describe('when correct cookie-secret header is provided', async function () {
before(async function () {
this.res = await request(this.frontend)
.get('/service-deployments-state')
.set('cookie-secret', process.env.COOKIE_SECRET);
});

after(function () {
delete this.res;
});

it('returns a status 200', async function () {
expect(this.res.status).to.equal(200);
});

it('returns the service enabled true', async function () {
expect(this.res.body.enabled).to.eql(true);
});
});
});

describe('Update service deployments state with cookie-secret', async function () {
beforeEach(function () {
process.env.COOKIE_SECRET = 'cookie-secret-value';
Expand Down

0 comments on commit 09db999

Please sign in to comment.