Skip to content

Commit

Permalink
INCIDEN-922: WIP access controls other lambdas [deploy]
Browse files Browse the repository at this point in the history
  • Loading branch information
Ryan-Andrews99 committed Sep 16, 2024
1 parent 0cf6821 commit 775d1bb
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 9 deletions.
60 changes: 54 additions & 6 deletions backend/api/src/handlers/dynamodb/dynamo-db-service.ts
Original file line number Diff line number Diff line change
@@ -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<APIGatewayProxyResult> => {
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) {
Expand All @@ -31,6 +49,13 @@ export const getDynamoDBEntriesHandler = async (event: APIGatewayProxyEvent): Pr

export const deleteDynamoDBClientEntriesHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
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;
Expand All @@ -39,27 +64,50 @@ 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<APIGatewayProxyResult> => {
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;
const serviceID = payload.serviceId;

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;
};
15 changes: 15 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,20 @@ 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;
}

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

const response = {statusCode: 200, body: JSON.stringify(userId)};
await client
.getServices(userId)
Expand Down
16 changes: 16 additions & 0 deletions backend/api/src/handlers/dynamodb/get-user.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
import {APIGatewayProxyEvent, APIGatewayProxyResult} from "aws-lambda";
import DynamoDbClient from "../../dynamodb-client";
import {validateAuthorisationHeader} from "../helper/validate-authorisation-header";

const client = new DynamoDbClient();

export const getUserHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
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
Expand Down
4 changes: 3 additions & 1 deletion backend/api/src/handlers/dynamodb/update-service-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ export type clientRegistryUpdateResponse = {
clientId: string;
updates: Updates;
};

//This lambda is called by the step function after updating the Client registry.

Check failure on line 13 in backend/api/src/handlers/dynamodb/update-service-client.ts

View workflow job for this annotation

GitHub Actions / Linting

Delete `·`
//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);

Expand Down
3 changes: 3 additions & 0 deletions backend/api/src/handlers/dynamodb/update-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Check failure on line 6 in backend/api/src/handlers/dynamodb/update-service.ts

View workflow job for this annotation

GitHub Actions / Linting

Delete `·`
//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")};
Expand Down
27 changes: 25 additions & 2 deletions backend/api/src/handlers/dynamodb/update-user.ts
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
34 changes: 34 additions & 0 deletions backend/api/src/handlers/step-functions/update-client.ts
Original file line number Diff line number Diff line change
@@ -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<APIGatewayProxyResult> => {
if (!event.body) {
return {statusCode: 400, body: "Invalid Request, missing body"};
}

const updateClientBody: {
serviceId: string;
updates: Record<string, string>;
} = 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);
};
1 change: 1 addition & 0 deletions express/src/services/self-service-services-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ export default class SelfServiceServicesService {
}

async globalSignOut(userEmail: string, accessToken: string): Promise<AxiosResponse> {
await this.validateToken(accessToken, "Global sign out");
await this.cognito.globalSignOut(accessToken);
return this.lambda.globalSignOut(userEmail);
}
Expand Down

0 comments on commit 775d1bb

Please sign in to comment.