diff --git a/packages/back-end/src/app/controllers/easy-genomics/organization/create-organization.lambda.ts b/packages/back-end/src/app/controllers/easy-genomics/organization/create-organization.lambda.ts index 6385eeb24..ab9605f01 100644 --- a/packages/back-end/src/app/controllers/easy-genomics/organization/create-organization.lambda.ts +++ b/packages/back-end/src/app/controllers/easy-genomics/organization/create-organization.lambda.ts @@ -5,15 +5,25 @@ import { buildResponse } from '@easy-genomics/shared-lib/src/app/utils/common'; import { APIGatewayProxyResult, APIGatewayProxyWithCognitoAuthorizerEvent, Handler } from 'aws-lambda'; import { v4 as uuidv4 } from 'uuid'; import { OrganizationService } from '@BE/services/easy-genomics/organization-service'; +import { validateSystemAdminAccess } from '@BE/utils/auth-utils'; const organizationService = new OrganizationService(); +/** + * This API is restricted to only the System Admin User who will oversee the + * creation of one or more Organizations in the Easy Genomics platform. + * + * @param event + */ export const handler: Handler = async ( event: APIGatewayProxyWithCognitoAuthorizerEvent, ): Promise => { console.log('EVENT: \n' + JSON.stringify(event, null, 2)); try { const userId = event.requestContext.authorizer.claims['cognito:username']; + if (!validateSystemAdminAccess(event)) { + throw new Error('Unauthorized access'); + } // Post Request Body const request: Organization = event.isBase64Encoded ? JSON.parse(atob(event.body!)) : JSON.parse(event.body!); // Data validation safety check diff --git a/packages/back-end/src/app/utils/auth-utils.ts b/packages/back-end/src/app/utils/auth-utils.ts new file mode 100644 index 000000000..934538335 --- /dev/null +++ b/packages/back-end/src/app/utils/auth-utils.ts @@ -0,0 +1,61 @@ +import { + LaboratoryAccess, + LaboratoryAccessDetails, + OrganizationAccess, + OrganizationAccessDetails, +} from '@easy-genomics/shared-lib/src/app/types/easy-genomics/user'; +import { APIGatewayProxyWithCognitoAuthorizerEvent } from 'aws-lambda'; +import { APIGatewayProxyEvent } from 'aws-lambda/trigger/api-gateway-proxy'; + +/** + * Helper function to check if the current User's Cognito session belongs to + * System Admin user in order to allow access to restricted APIs. + * @param event + */ +export function validateSystemAdminAccess(event: APIGatewayProxyWithCognitoAuthorizerEvent): Boolean { + const cognitoGroup: string = event.requestContext.authorizer.claims['cognito:groups']; + return cognitoGroup === 'SystemAdmin'; +} + +/** + * Helper function to check if an authenticated User's JWT OrganizationAccess + * metadata allows access to the requested Organization / Laboratory. + * @param event + * @param organizationId + * @param laboratoryId + */ +export function validateOrganizationAccess( + event: APIGatewayProxyEvent, + organizationId: string, + laboratoryId?: string, +): Boolean { + try { + const orgAccessMetadata: string | undefined = event.requestContext.authorizer?.claims.OrganizationAccess; + if (!orgAccessMetadata) { + return false; + } + + const organizationAccess: OrganizationAccess = JSON.parse(orgAccessMetadata); + const organizationAccessDetails: OrganizationAccessDetails | undefined = organizationAccess[organizationId]; + if (!organizationAccessDetails || (organizationAccessDetails && organizationAccessDetails.Status !== 'Active')) { + return false; + } + + if (laboratoryId) { + const laboratoryAccess: LaboratoryAccess | undefined = organizationAccessDetails.LaboratoryAccess; + if (!laboratoryAccess) { + return false; + } + + const laboratoryAccessDetails: LaboratoryAccessDetails | undefined = laboratoryAccess[laboratoryId]; + if (!laboratoryAccessDetails || (laboratoryAccessDetails && laboratoryAccessDetails.Status !== 'Active')) { + return false; + } + } + + return true; + } catch (error) { + console.error(error); + return false; + } +} diff --git a/packages/back-end/src/app/utils/rest-api-utils.ts b/packages/back-end/src/app/utils/rest-api-utils.ts index bb0d6eb96..d70a93a34 100644 --- a/packages/back-end/src/app/utils/rest-api-utils.ts +++ b/packages/back-end/src/app/utils/rest-api-utils.ts @@ -1,9 +1,3 @@ -import { - LaboratoryAccess, - LaboratoryAccessDetails, - OrganizationAccess, - OrganizationAccessDetails, -} from '@easy-genomics/shared-lib/src/app/types/easy-genomics/user'; import { APIGatewayProxyEvent } from 'aws-lambda/trigger/api-gateway-proxy'; export const enum REST_API_METHOD { @@ -81,46 +75,3 @@ export function getApiParameters(event: APIGatewayProxyEvent): URLSearchParams { return parameters; } - -/** - * Helper function to check if an authenticated User's JWT OrganizationAccess - * metadata allows access to the requested Organization / Laboratory. - * @param event - * @param organizationId - * @param laboratoryId - */ -export function validateOrganizationAccess( - event: APIGatewayProxyEvent, - organizationId: string, - laboratoryId?: string, -): Boolean { - try { - const orgAccessMetadata: string | undefined = event.requestContext.authorizer?.claims.OrganizationAccess; - if (!orgAccessMetadata) { - return false; - } - - const organizationAccess: OrganizationAccess = JSON.parse(orgAccessMetadata); - const organizationAccessDetails: OrganizationAccessDetails | undefined = organizationAccess[organizationId]; - if (!organizationAccessDetails || (organizationAccessDetails && organizationAccessDetails.Status !== 'Active')) { - return false; - } - - if (laboratoryId) { - const laboratoryAccess: LaboratoryAccess | undefined = organizationAccessDetails.LaboratoryAccess; - if (!laboratoryAccess) { - return false; - } - - const laboratoryAccessDetails: LaboratoryAccessDetails | undefined = laboratoryAccess[laboratoryId]; - if (!laboratoryAccessDetails || (laboratoryAccessDetails && laboratoryAccessDetails.Status !== 'Active')) { - return false; - } - } - - return true; - } catch (error) { - console.error(error); - return false; - } -}