Skip to content

Commit

Permalink
INCIDEN-922: Adds access control to the getService handler [deploy]
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan-Andrews99 committed Sep 18, 2024
1 parent 5000b37 commit 73437b0
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 13 deletions.
17 changes: 17 additions & 0 deletions backend/api/src/handlers/dynamodb/get-services.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {APIGatewayProxyEvent, APIGatewayProxyResult} from "aws-lambda";
import DynamoDbClient from "../../dynamodb-client";
import {validateAuthorisationHeader} from "../helper/validate-authorisation-header";

const client = new DynamoDbClient();

Expand All @@ -9,6 +10,22 @@ export const getServicesHandler = async (event: APIGatewayProxyEvent): Promise<A
return noUserIdResponse;
}

const authHeader = event.headers.Authorization;
const authorisationHeaderValidation = validateAuthorisationHeader(authHeader);

if (!authorisationHeaderValidation.valid) {
return authorisationHeaderValidation.errorResponse;
}

const userIdWithoutPrefix = userId.includes("user#") ? userId.substring("user#".length) : userId;

if (userIdWithoutPrefix !== authorisationHeaderValidation.userId) {
return {
statusCode: 403,
body: "Forbidden"
};
}

const response = {statusCode: 200, body: JSON.stringify(userId)};
await client
.getServices(userId)
Expand Down
55 changes: 42 additions & 13 deletions backend/api/tests/handlers/dynamodb/get-services.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,54 @@ import {getServicesHandler} from "../../../src/handlers/dynamodb/get-services";
import DynamoDbClient from "../../../src/dynamodb-client";
import {constructTestApiGatewayEvent} from "../utils";
import {GetItemCommandOutput} from "@aws-sdk/client-dynamodb";
import {TEST_USER_ID} from "../constants";
import {TEST_ACCESS_TOKEN, TEST_DATA_TABLE_ITEM, TEST_USER_ID} from "../constants";

describe("getServicesHandler tests", () => {
beforeEach(() => {
jest.clearAllMocks();
});

it("returns a 400 when there is no userId Path parameter and does not call the dynamo client", async () => {
const serviceHandlerResponse = await getServicesHandler(constructTestApiGatewayEvent());
expect(serviceHandlerResponse).toStrictEqual({
statusCode: 400,
body: JSON.stringify("No userId request parameter supplied")
});
});

it("returns a 403 if the userId in the pathParams does not match the access token", async () => {
const mockDynamoResponse: GetItemCommandOutput = {
$metadata: {},
Item: TEST_DATA_TABLE_ITEM
};
const getServicesSpy = jest.spyOn(DynamoDbClient.prototype, "getServices").mockResolvedValue(mockDynamoResponse);

const testApiGatewayEvent = constructTestApiGatewayEvent({
body: "",
pathParameters: {userId: "aDifferentUserId"},
headers: {Authorization: `Bearer ${TEST_ACCESS_TOKEN}`}
});
const serviceHandlerResponse = await getServicesHandler(testApiGatewayEvent);

expect(getServicesSpy).not.toHaveBeenCalled();
expect(serviceHandlerResponse).toStrictEqual({
statusCode: 403,
body: "Forbidden"
});
});

it("calls the dynamo client with a get command with the expected values and returns a 200 with the expected response body", async () => {
const mockDynamoResponse: GetItemCommandOutput = {
$metadata: {}
$metadata: {},
Item: TEST_DATA_TABLE_ITEM
};
const getServicesSpy = jest.spyOn(DynamoDbClient.prototype, "getServices").mockResolvedValue(mockDynamoResponse);

const testApiGatewayEvent = constructTestApiGatewayEvent({body: "", pathParameters: {userId: TEST_USER_ID}});
const testApiGatewayEvent = constructTestApiGatewayEvent({
body: "",
pathParameters: {userId: TEST_USER_ID},
headers: {Authorization: `Bearer ${TEST_ACCESS_TOKEN}`}
});
const serviceHandlerResponse = await getServicesHandler(testApiGatewayEvent);

expect(getServicesSpy).toHaveBeenCalledWith(TEST_USER_ID);
Expand All @@ -30,7 +64,11 @@ describe("getServicesHandler tests", () => {
const error = "SomeAwsError";
const getServicesSpy = jest.spyOn(DynamoDbClient.prototype, "getServices").mockRejectedValue(error);

const testApiGatewayEvent = constructTestApiGatewayEvent({body: "", pathParameters: {userId: TEST_USER_ID}});
const testApiGatewayEvent = constructTestApiGatewayEvent({
body: "",
pathParameters: {userId: TEST_USER_ID},
headers: {Authorization: `Bearer ${TEST_ACCESS_TOKEN}`}
});
const serviceHandlerResponse = await getServicesHandler(testApiGatewayEvent);
expect(getServicesSpy).toHaveBeenCalledWith(TEST_USER_ID);

Expand All @@ -39,13 +77,4 @@ describe("getServicesHandler tests", () => {
body: JSON.stringify(error)
});
});

it("returns a 400 when there is no userId Path parameter and does not call the dynamo client", async () => {
const error = "No userId request parameter supplied";
const serviceHandlerResponse = await getServicesHandler(constructTestApiGatewayEvent());
expect(serviceHandlerResponse).toStrictEqual({
statusCode: 400,
body: JSON.stringify(error)
});
});
});

0 comments on commit 73437b0

Please sign in to comment.