From ffb21b3fd0f5287f821fe67a4a9d8c03c0e1d909 Mon Sep 17 00:00:00 2001 From: Ryan Andrews Date: Tue, 17 Sep 2024 11:05:40 +0100 Subject: [PATCH] INCIDEN-922: Adds access control to the getService handler [deploy] --- .../api/src/handlers/dynamodb/get-services.ts | 17 ++++++ .../handlers/dynamodb/get-services.test.ts | 55 ++++++++++++++----- 2 files changed, 59 insertions(+), 13 deletions(-) diff --git a/backend/api/src/handlers/dynamodb/get-services.ts b/backend/api/src/handlers/dynamodb/get-services.ts index 9753c7f1b..f71b00af2 100644 --- a/backend/api/src/handlers/dynamodb/get-services.ts +++ b/backend/api/src/handlers/dynamodb/get-services.ts @@ -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(); @@ -9,6 +10,22 @@ export const getServicesHandler = async (event: APIGatewayProxyEvent): Promise { 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); @@ -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); @@ -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) - }); - }); });