Skip to content

Commit

Permalink
CMDCT-3165: Remove State Rep Role and Reports Attribute from MCR Stat…
Browse files Browse the repository at this point in the history
…e Users (#11552)
  • Loading branch information
karla-vm authored Jan 8, 2024
1 parent e23abdb commit af6f85a
Show file tree
Hide file tree
Showing 25 changed files with 21 additions and 486 deletions.
1 change: 0 additions & 1 deletion services/app-api/handlers/reports/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import s3Lib from "../../utils/s3/s3-lib";
jest.mock("../../utils/auth/authorization", () => ({
isAuthorized: jest.fn().mockResolvedValue(true),
hasPermissions: jest.fn().mockReturnValue(true),
hasReportAccess: jest.fn().mockReturnValue(true),
}));

jest.mock("../../utils/debugging/debug-lib", () => ({
Expand Down
15 changes: 2 additions & 13 deletions services/app-api/handlers/reports/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@ import handler from "../handler-lib";
import dynamoDb from "../../utils/dynamo/dynamodb-lib";
import { hasReportPathParams } from "../../utils/dynamo/hasReportPathParams";
import s3Lib, { getFieldDataKey } from "../../utils/s3/s3-lib";
import {
hasReportAccess,
hasPermissions,
} from "../../utils/auth/authorization";
import { hasPermissions } from "../../utils/auth/authorization";
import {
validateData,
validateFieldData,
Expand Down Expand Up @@ -35,7 +32,7 @@ import {
} from "../../utils/reports/reports";

export const createReport = handler(async (event, _context) => {
if (!hasPermissions(event, [UserRoles.STATE_USER, UserRoles.STATE_REP])) {
if (!hasPermissions(event, [UserRoles.STATE_USER])) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
Expand Down Expand Up @@ -73,14 +70,6 @@ export const createReport = handler(async (event, _context) => {
};
}

// Return a 403 status if the user does not have access to this report
if (!hasReportAccess(event, reportType)) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
};
}

const reportBucket = reportBuckets[reportType];
const reportTable = reportTables[reportType];

Expand Down
22 changes: 0 additions & 22 deletions services/app-api/handlers/reports/fetch.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@ import { StatusCodes } from "../../utils/types";
jest.mock("../../utils/auth/authorization", () => ({
isAuthorized: jest.fn().mockReturnValue(true),
hasPermissions: jest.fn().mockReturnValue(true),
hasReportAccess: jest.fn().mockReturnValue(true),
}));
const mockAuthUtil = require("../../utils/auth/authorization");

jest.mock("../../utils/debugging/debug-lib", () => ({
init: jest.fn(),
Expand Down Expand Up @@ -64,16 +62,6 @@ describe("Test fetchReport API method", () => {
expect(res.statusCode).toBe(StatusCodes.NOT_FOUND);
});

test("Test no report access fetch throws 403 error", async () => {
// fail report access
mockAuthUtil.hasReportAccess.mockReturnValueOnce(false);
const res = await fetchReport(testReadEvent, null);

expect(res.statusCode).toBe(403);
expect(res.body).toContain(error.UNAUTHORIZED);
jest.clearAllMocks();
});

test("Test Successful Report Fetch w/ Incomplete Report", async () => {
mockDocumentClient.get.promise.mockReturnValueOnce({
Item: mockDynamoData,
Expand Down Expand Up @@ -160,14 +148,4 @@ describe("Test fetchReportsByState API method", () => {
expect(res.statusCode).toBe(400);
expect(res.body).toContain(error.NO_KEY);
});

test("Test no report access fetch throws 403 error", async () => {
// fail report access
mockAuthUtil.hasReportAccess.mockReturnValueOnce(false);
const res = await fetchReportsByState(testReadEventByState, null);

expect(res.statusCode).toBe(403);
expect(res.body).toContain(error.UNAUTHORIZED);
jest.clearAllMocks();
});
});
17 changes: 0 additions & 17 deletions services/app-api/handlers/reports/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
calculateCompletionStatus,
isComplete,
} from "../../utils/validation/completionStatus";
import { hasReportAccess } from "../../utils/auth/authorization";
// types
import { AnyObject, isState, S3Get, StatusCodes } from "../../utils/types";

Expand All @@ -38,14 +37,6 @@ export const fetchReport = handler(async (event, _context) => {
};
}

// Return a 403 status if the user does not have access to this report
if (!hasReportAccess(event, reportType!)) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
};
}

const reportTable = reportTables[reportType as keyof typeof reportTables];
const reportBucket = reportBuckets[reportType as keyof typeof reportBuckets];

Expand Down Expand Up @@ -140,14 +131,6 @@ export const fetchReportsByState = handler(async (event, _context) => {

const reportType = event.pathParameters?.reportType;

// Return a 403 status if the user does not have access to this report
if (!hasReportAccess(event, reportType!)) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
};
}

const reportTable = reportTables[reportType as keyof typeof reportTables];

const queryParams: DynamoFetchParams = {
Expand Down
7 changes: 0 additions & 7 deletions services/app-api/handlers/reports/submit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import { StatusCodes } from "../../utils/types/other";
jest.mock("../../utils/auth/authorization", () => ({
isAuthorized: jest.fn().mockReturnValue(true),
hasPermissions: jest.fn().mockReturnValue(true),
hasReportAccess: jest.fn().mockReturnValueOnce(false).mockReturnValue(true),
}));

jest.mock("../../utils/debugging/debug-lib", () => ({
Expand All @@ -35,12 +34,6 @@ const testSubmitEvent: APIGatewayProxyEvent = {
};

describe("Test submitReport API method", () => {
test("Test report submission by a state user without access to a report type throws 403 error", async () => {
const res = await submitReport(testSubmitEvent, null);

expect(res.statusCode).toBe(403);
expect(res.body).toContain(error.UNAUTHORIZED);
});
test("Test Report not found in DynamoDB", async () => {
mockDocumentClient.get.promise.mockReturnValueOnce({ Item: undefined });
const res = await submitReport(testSubmitEvent, null);
Expand Down
15 changes: 2 additions & 13 deletions services/app-api/handlers/reports/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,7 @@ import { bool } from "aws-sdk/clients/signer";
import jwtDecode from "jwt-decode";
import handler from "../handler-lib";
// utils
import {
hasReportAccess,
hasPermissions,
} from "../../utils/auth/authorization";
import { hasPermissions } from "../../utils/auth/authorization";
import {
error,
reportBuckets,
Expand Down Expand Up @@ -38,7 +35,7 @@ export const submitReport = handler(async (event, _context) => {
};
}

if (!hasPermissions(event, [UserRoles.STATE_USER, UserRoles.STATE_REP])) {
if (!hasPermissions(event, [UserRoles.STATE_USER])) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
Expand All @@ -54,14 +51,6 @@ export const submitReport = handler(async (event, _context) => {
};
}

// Return a 403 status if the user does not have access to this report
if (!hasReportAccess(event, reportType!)) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
};
}

const reportTable = reportTables[reportType as keyof typeof reportTables];
const reportBucket = reportBuckets[reportType as keyof typeof reportBuckets];

Expand Down
11 changes: 0 additions & 11 deletions services/app-api/handlers/reports/update.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { StatusCodes } from "../../utils/types";
jest.mock("../../utils/auth/authorization", () => ({
isAuthorized: jest.fn().mockResolvedValue(true),
hasPermissions: jest.fn(() => {}),
hasReportAccess: jest.fn().mockReturnValue(true),
}));
const mockAuthUtil = require("../../utils/auth/authorization");

Expand Down Expand Up @@ -90,22 +89,12 @@ describe("Test updateReport and archiveReport unauthorized calls", () => {
expect(res.statusCode).toBe(403);
expect(res.body).toContain(error.UNAUTHORIZED);
});

test("Test report update with no proper report access throws 403 error", async () => {
// fail report access check
mockAuthUtil.hasReportAccess.mockReturnValue(false);
const res = await updateReport(updateEvent, null);

expect(res.statusCode).toBe(403);
expect(res.body).toContain(error.UNAUTHORIZED);
});
});

describe("Test updateReport API method", () => {
beforeAll(() => {
// pass state auth check
mockAuthUtil.hasPermissions.mockReturnValue(true);
mockAuthUtil.hasReportAccess.mockReturnValue(true);
});
afterEach(() => {
jest.clearAllMocks();
Expand Down
15 changes: 2 additions & 13 deletions services/app-api/handlers/reports/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,7 @@ import { fetchReport } from "./fetch";
// utils
import dynamoDb from "../../utils/dynamo/dynamodb-lib";
import { hasReportPathParams } from "../../utils/dynamo/hasReportPathParams";
import {
hasReportAccess,
hasPermissions,
} from "../../utils/auth/authorization";
import { hasPermissions } from "../../utils/auth/authorization";
import s3Lib, {
getFieldDataKey,
getFormTemplateKey,
Expand Down Expand Up @@ -92,7 +89,7 @@ export const updateReport = handler(async (event, context) => {
}

// Ensure user has correct permissions to update a report.
if (!hasPermissions(event, [UserRoles.STATE_USER, UserRoles.STATE_REP])) {
if (!hasPermissions(event, [UserRoles.STATE_USER])) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
Expand Down Expand Up @@ -122,14 +119,6 @@ export const updateReport = handler(async (event, context) => {

const { formTemplateId, fieldDataId, reportType } = currentReport;

// Return a 403 status if the user does not have access to this report
if (!hasReportAccess(event, reportType!)) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
};
}

const reportBucket = reportBuckets[reportType as keyof typeof reportBuckets];
const reportTable = reportTables[reportType as keyof typeof reportTables];

Expand Down
23 changes: 1 addition & 22 deletions services/app-api/utils/auth/authorization.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { proxyEvent } from "../testing/proxyEvent";
import { hasReportAccess, hasPermissions, isAuthorized } from "./authorization";
import { hasPermissions, isAuthorized } from "./authorization";
import { UserRoles } from "../types/users";

const mockVerifier = jest.fn();
Expand Down Expand Up @@ -101,24 +101,3 @@ describe("Check user has permissions", () => {
expect(hasPermissions(noApiKeyEvent, [UserRoles.ADMIN])).toBeFalsy();
});
});

describe("Check user has access to reports", () => {
beforeEach(() => {
mockedDecode.mockReturnValue({
"custom:reports": "MCPAR",
});
});

test("has access should pass when the asked for report is the given report", () => {
expect(hasReportAccess(apiKeyEvent, "MCPAR")).toBeTruthy();
});
test("has permissions should fail when the asked for role is the given role", () => {
mockedDecode.mockReturnValue({
"custom:cms_roles": "mdctmcr-state-user",
});
expect(hasReportAccess(apiKeyEvent, "MLR")).toBeFalsy();
});
test("has permissions should fail when the api token is missing", () => {
expect(hasReportAccess(noApiKeyEvent, "NAAAR")).toBeFalsy();
});
});
29 changes: 0 additions & 29 deletions services/app-api/utils/auth/authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { UserRoles } from "../types";

interface DecodedToken {
"custom:cms_roles": UserRoles;
"custom:reports": string;
}

const loadCognitoValues = async () => {
Expand Down Expand Up @@ -93,31 +92,3 @@ export const hasPermissions = (

return isAllowed;
};

export const hasReportAccess = (
event: APIGatewayProxyEvent,
reportType: string
) => {
let hasAccess = false;
// decode the idToken
if (event?.headers["x-api-key"]) {
const decoded = jwt_decode(event.headers["x-api-key"]) as DecodedToken;
const idmUserRoles = decoded["custom:cms_roles"];
const isStateUser = idmUserRoles
?.split(",")
.find((role) => role === "mdctmcr-state-user") as UserRoles;

// check report access for state users only
if (!isStateUser) {
return true;
}
const reports = decoded["custom:reports"];
const allowedReports = reports
?.split(",")
.find((report: string) => report.includes(reportType)) as string;
if (allowedReports) {
hasAccess = true;
}
}
return hasAccess;
};
1 change: 0 additions & 1 deletion services/app-api/utils/testing/setupJest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,6 @@ export const mockApiKey = sign(
"custom:cms_roles": "mdctmcr-state-user",
given_name: "Thelonious",
"custom:cms_state": "MN",
"custom:reports": "MCPAR,MLR,NAAAR",
family_name: "States",
email: "[email protected]",
},
Expand Down
1 change: 0 additions & 1 deletion services/app-api/utils/types/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export enum UserRoles {
HELP_DESK = "mdctmcr-help-desk", // "MDCT MCR Help Desk"
INTERNAL = "mdctmcr-internal-user", // "MDCT MCR Internal User"
APPROVER = "mdctmcr-approver", // "MDCT MCR Approver"
STATE_REP = "mdctmcr-state-rep", // "MDCT MCR State Representative"
STATE_USER = "mdctmcr-state-user", // "MDCT MCR State User"
}

Expand Down
Loading

0 comments on commit af6f85a

Please sign in to comment.