diff --git a/backend/api/src/handlers/dynamodb/dynamo-db-service.ts b/backend/api/src/handlers/dynamodb/dynamo-db-service.ts index d959f92d6..14cf494e4 100644 --- a/backend/api/src/handlers/dynamodb/dynamo-db-service.ts +++ b/backend/api/src/handlers/dynamodb/dynamo-db-service.ts @@ -1,15 +1,33 @@ import DynamoDbClient from "../../dynamodb-client"; import console from "console"; import {APIGatewayProxyEvent, APIGatewayProxyResult} from "aws-lambda"; +import {validateAuthorisationHeader} from "../helper/validate-authorisation-header"; const dynamoDBClient = new DynamoDbClient(); export const getDynamoDBEntriesHandler = async (event: APIGatewayProxyEvent): Promise => { console.log("dynamo-db-inspector - In getDynamoDBEntriesHandler"); + const authHeader = event.headers.Authorization; + + const authorisationHeaderValidation = validateAuthorisationHeader(authHeader); + + if (!authorisationHeaderValidation.valid) { + return authorisationHeaderValidation.errorResponse; + } + const response = {statusCode: 404, body: JSON.stringify("")}; const userEmail = event.pathParameters?.userEmail; + const getUserResponse = await dynamoDBClient.getUser(authorisationHeaderValidation.userId); + + if (!getUserResponse.Item || getUserResponse.Item.email.S !== userEmail) { + return { + statusCode: 403, + body: "Forbidden" + }; + } + const result = await dynamoDBClient.getListOfClients(); if (userEmail == null || result == null || result.Items == null) { @@ -31,6 +49,13 @@ export const getDynamoDBEntriesHandler = async (event: APIGatewayProxyEvent): Pr export const deleteDynamoDBClientEntriesHandler = async (event: APIGatewayProxyEvent): Promise => { console.log("dynamo-db-inspector - In deleteDynamoDBClientEntriesHandler"); + const authHeader = event.headers.Authorization; + + const authorisationHeaderValidation = validateAuthorisationHeader(authHeader); + + if (!authorisationHeaderValidation.valid) { + return authorisationHeaderValidation.errorResponse; + } const response = {statusCode: 500, body: JSON.stringify("")}; const payload = event?.body ? JSON.parse(event.body as string) : event; @@ -39,16 +64,32 @@ export const deleteDynamoDBClientEntriesHandler = async (event: APIGatewayProxyE if (userID == null || serviceID == null) { throw new Error("No details provided for DeleteDynamoDBClientEntries"); - } else { - await dynamoDBClient.deleteDynamoDBClientEntries(userID, serviceID); - response.statusCode = 200; } + const isUserAuthorised = await dynamoDBClient.checkServiceUserExists(serviceID, authorisationHeaderValidation.userId); + + if (!isUserAuthorised || userID !== authorisationHeaderValidation.userId) { + return { + statusCode: 403, + body: "Forbidden" + }; + } + + await dynamoDBClient.deleteDynamoDBClientEntries(userID, serviceID); + response.statusCode = 200; + return response; }; export const deleteDynamoDBServiceEntriesHandler = async (event: APIGatewayProxyEvent): Promise => { console.log("dynamo-db-inspector - In deleteDynamoDBServiceEntriesHandler"); + const authHeader = event.headers.Authorization; + + const authorisationHeaderValidation = validateAuthorisationHeader(authHeader); + + if (!authorisationHeaderValidation.valid) { + return authorisationHeaderValidation.errorResponse; + } const response = {statusCode: 500, body: JSON.stringify("")}; const payload = event?.body ? JSON.parse(event.body as string) : event; @@ -56,10 +97,17 @@ export const deleteDynamoDBServiceEntriesHandler = async (event: APIGatewayProxy if (serviceID == null) { throw new Error("No Service ID provided for DeleteDynamoDBServiceEntries"); - } else { - await dynamoDBClient.deleteDynamoDBServiceEntries(serviceID); - response.statusCode = 200; } + const isUserAuthorised = await dynamoDBClient.checkServiceUserExists(serviceID, authorisationHeaderValidation.userId); + + if (!isUserAuthorised) { + return { + statusCode: 403, + body: "Forbidden" + }; + } + await dynamoDBClient.deleteDynamoDBServiceEntries(serviceID); + response.statusCode = 200; return response; }; diff --git a/backend/api/src/handlers/dynamodb/get-services.ts b/backend/api/src/handlers/dynamodb/get-services.ts index 9753c7f1b..a347beb87 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,20 @@ export const getServicesHandler = async (event: APIGatewayProxyEvent): Promise => { const cognitoId = JSON.parse(event.body as string); + const authHeader = event.headers.Authorization; + + const authorisationHeaderValidation = validateAuthorisationHeader(authHeader); + + if (!authorisationHeaderValidation.valid) { + return authorisationHeaderValidation.errorResponse; + } + + if (authorisationHeaderValidation.userId !== cognitoId) { + return { + statusCode: 403, + body: "Forbidden" + }; + } + const response = {statusCode: 200, body: JSON.stringify("OK")}; await client diff --git a/backend/api/src/handlers/dynamodb/update-service-client.ts b/backend/api/src/handlers/dynamodb/update-service-client.ts index 9231b6db5..10b5c6b15 100644 --- a/backend/api/src/handlers/dynamodb/update-service-client.ts +++ b/backend/api/src/handlers/dynamodb/update-service-client.ts @@ -10,7 +10,9 @@ export type clientRegistryUpdateResponse = { clientId: string; updates: Updates; }; - + //This lambda is called by the step function after updating the Client registry. +//Given we authorise the user before we call the step function, there is no need +//to implement additional authorisation here export const updateServiceClientHandler = async (event: handlerInvokeEvent): Promise<{statusCode: number; body: string}> => { const payload: clientRegistryUpdateResponse = JSON.parse(event.body); diff --git a/backend/api/src/handlers/dynamodb/update-service.ts b/backend/api/src/handlers/dynamodb/update-service.ts index 3fa9cd1a0..1515d776e 100644 --- a/backend/api/src/handlers/dynamodb/update-service.ts +++ b/backend/api/src/handlers/dynamodb/update-service.ts @@ -3,6 +3,9 @@ import {handlerInvokeEvent} from "../handler-utils"; const client = new DynamoDbClient(); + //This lambda is called by the step function after updating the Client registry. +//Given we authorise the user before we call the step function, there is no need +//to implement additional authorisation here export const updateServiceHandler = async (event: handlerInvokeEvent): Promise<{statusCode: number; body: string}> => { const body = JSON.parse(event.body as string); const response = {statusCode: 200, body: JSON.stringify("OK")}; diff --git a/backend/api/src/handlers/dynamodb/update-user.ts b/backend/api/src/handlers/dynamodb/update-user.ts index 3b35d11d2..c3eb9476c 100644 --- a/backend/api/src/handlers/dynamodb/update-user.ts +++ b/backend/api/src/handlers/dynamodb/update-user.ts @@ -1,11 +1,34 @@ +import {APIGatewayEvent} from "aws-lambda"; import DynamoDbClient from "../../dynamodb-client"; -import {handlerInvokeEvent} from "../handler-utils"; +import {validateAuthorisationHeader} from "../helper/validate-authorisation-header"; const client = new DynamoDbClient(); -export const updateUserHandler = async (event: handlerInvokeEvent): Promise<{statusCode: number; body: string}> => { +export const updateUserHandler = async (event: APIGatewayEvent): Promise<{statusCode: number; body: string}> => { const body = JSON.parse(event.body as string); const response = {statusCode: 200, body: JSON.stringify("OK")}; + const userId = body.userId; + + if (!userId) { + return { + statusCode: 400, + body: "No userId provided in request body" + }; + } + + const authHeader = event.headers.Authorization; + const authorisationHeaderValidation = validateAuthorisationHeader(authHeader); + + if (!authorisationHeaderValidation.valid) { + return authorisationHeaderValidation.errorResponse; + } + + if (userId !== authorisationHeaderValidation.userId) { + return { + statusCode: 403, + body: "Forbidden" + }; + } await client .updateUser(body.userId, body.cognitoUserId, body.updates) diff --git a/backend/api/src/handlers/step-functions/update-client.ts b/backend/api/src/handlers/step-functions/update-client.ts index 881f6c996..7b21abb5f 100644 --- a/backend/api/src/handlers/step-functions/update-client.ts +++ b/backend/api/src/handlers/step-functions/update-client.ts @@ -1,6 +1,40 @@ import {APIGatewayProxyEvent, APIGatewayProxyResult, Context} from "aws-lambda"; import {stepFunctionHandler} from "./step-function-handler"; +import {validateAuthorisationHeader} from "../helper/validate-authorisation-header"; +import DynamoDbClient from "../../dynamodb-client"; + +const client = new DynamoDbClient(); export const doUpdateClientHandler = async (event: APIGatewayProxyEvent, context: Context): Promise => { + if (!event.body) { + return {statusCode: 400, body: "Invalid Request, missing body"}; + } + + const updateClientBody: { + serviceId: string; + updates: Record; + } = JSON.parse(event.body); + + const serviceId = updateClientBody.serviceId; + + if (!serviceId) { + return {statusCode: 400, body: "Invalid Request, missing service ID"}; + } + + const authHeaderValidationResult = validateAuthorisationHeader(event.headers.Authorization); + + if (!authHeaderValidationResult.valid) { + return authHeaderValidationResult.errorResponse; + } + + const isUserAuthorised = await client.checkServiceUserExists(serviceId, authHeaderValidationResult.userId); + + if (!isUserAuthorised) { + return { + statusCode: 403, + body: "Forbidden" + }; + } + return stepFunctionHandler(event, context); }; diff --git a/express/src/services/self-service-services-service.ts b/express/src/services/self-service-services-service.ts index 151c384ae..25cbe8906 100644 --- a/express/src/services/self-service-services-service.ts +++ b/express/src/services/self-service-services-service.ts @@ -285,6 +285,7 @@ export default class SelfServiceServicesService { } async globalSignOut(userEmail: string, accessToken: string): Promise { + await this.validateToken(accessToken, "Global sign out"); await this.cognito.globalSignOut(accessToken); return this.lambda.globalSignOut(userEmail); }