Service account checkpoint

This commit is contained in:
Tuan Dang
2023-03-19 17:01:36 +07:00
parent 8fb473c57c
commit 3a0ce7c084
15 changed files with 356 additions and 136 deletions
+15 -17
View File
@@ -1,5 +1,9 @@
import * as Sentry from '@sentry/node';
import { Membership, Key } from '../models';
import {
MembershipNotFoundError,
BadRequestError
} from '../utils/errors';
/**
* Validate that user with id [userId] is a member of workspace with id [workspaceId]
@@ -19,23 +23,17 @@ const validateMembership = async ({
acceptedRoles: string[];
}) => {
let membership;
//TODO: Refactor code to take advantage of using RequestError. It's possible to create new types of errors for more detailed errors
try {
membership = await Membership.findOne({
user: userId,
workspace: workspaceId
}).populate("workspace");
if (!membership) throw new Error('Failed to find membership');
if (!acceptedRoles.includes(membership.role)) {
throw new Error('Failed to validate membership role');
}
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to validate membership');
const membership = await Membership.findOne({
user: userId,
workspace: workspaceId
}).populate("workspace");
if (!membership) {
throw MembershipNotFoundError({ message: 'Failed to find workspace membership' });
}
if (!acceptedRoles.includes(membership.role)) {
throw BadRequestError({ message: 'Failed to validate workspace membership role' });
}
return membership;
+31 -23
View File
@@ -1,40 +1,48 @@
import * as Sentry from '@sentry/node';
import { Types } from 'mongoose';
import { MembershipOrg, Workspace, Membership, Key } from '../models';
import {
MembershipOrgNotFoundError,
BadRequestError
} from '../utils/errors';
/**
* Validate that user with id [userId] is a member of organization with id [organizationId]
* and has at least one of the roles in [acceptedRoles]
*
* @param {Object} obj
* @param {Types.ObjectId} obj.userId
* @param {Types.ObjectId} obj.organizationId
* @param {String[]} obj.acceptedRoles
*/
const validateMembership = async ({
const validateMembershipOrg = async ({
userId,
organizationId,
acceptedRoles
acceptedRoles,
acceptedStatuses
}: {
userId: string;
organizationId: string;
userId: Types.ObjectId;
organizationId: Types.ObjectId;
acceptedRoles: string[];
acceptedStatuses: string[];
}) => {
let membership;
try {
membership = await MembershipOrg.findOne({
user: new Types.ObjectId(userId),
organization: new Types.ObjectId(organizationId)
});
if (!membership) throw new Error('Failed to find organization membership');
if (!acceptedRoles.includes(membership.role)) {
throw new Error('Failed to validate organization membership role');
}
} catch (err) {
Sentry.setUser(null);
Sentry.captureException(err);
throw new Error('Failed to validate organization membership');
const membershipOrg = await MembershipOrg.findOne({
user: userId,
organization: organizationId
});
if (!membershipOrg) {
throw MembershipOrgNotFoundError({ message: 'Failed to find organization membership' });
}
return membership;
if (!acceptedRoles.includes(membershipOrg.role)) {
throw BadRequestError({ message: 'Failed to validate organization membership role' });
}
if (!acceptedStatuses.includes(membershipOrg.status)) {
throw BadRequestError({ message: 'Failed to validate organization membership status' });
}
return membershipOrg;
}
/**
@@ -156,7 +164,7 @@ const deleteMembershipOrg = async ({
};
export {
validateMembership,
validateMembershipOrg,
findMembershipOrg,
addMembershipsOrg,
deleteMembershipOrg
+110
View File
@@ -0,0 +1,110 @@
import { Types } from 'mongoose';
import {
Workspace,
ServiceAccount,
ServiceAccountKey
} from '../models';
import {
WorkspaceNotFoundError,
ServiceAccountNotFoundError,
ServiceAccountKeyNotFoundError
} from '../utils/errors';
import {
PERMISSION_SA_WORKSPACE_READ,
PERMISSION_SA_WORKSPACE_WRITE,
PERMISSION_SA_SET
} from '../variables';
/**
* Validate that user with id [userId] can provision the permission
* named [name] for a service account with id [serviceAccountId] and
* optionally workspace with id [workspaceId] and environment [environment]
* @param {Object} obj
* @param {String} obj.name - name of permission to create
* @param {Types.ObjectId} userId - id of user creating the permission
* @param {Types.ObjectId} serviceAccountId - id of service account that permission will be bound to
* @param {Types.ObjectId} workspaceId - id of workspace that permission concerns
* @param {Types.ObjectId} workspaceId - id of service account that permission will be bound to
*/
const validateCreateServiceAccountPermission = async ({
name,
userId,
serviceAccountId,
workspaceId,
environment
}: {
name: string;
userId: Types.ObjectId;
serviceAccountId: Types.ObjectId,
workspaceId?: Types.ObjectId;
environment?: string;
}) => {
// TODO: as we upgrade user permissions to be more global, then we should take into account
// the user's permissions as it concerns to being able to interact with service accounts
if (!PERMISSION_SA_SET.has(name)) throw new Error(`${name} is not a valid permission name`);
if ([
PERMISSION_SA_WORKSPACE_READ,
PERMISSION_SA_WORKSPACE_WRITE
].includes(name)) {
if (workspaceId && environment) {
// case: either workspace id [workspaceId] or environment name [environment] is being passed in
// (i.e. validating a service account permission concerning a workspace and/or environment)
const workspace = await Workspace.findById(workspaceId);
if (!workspace) {
// case: workspace does not exist
throw WorkspaceNotFoundError({ message: 'Failed to locate workspace' });
}
if (!workspace.environments.some((env) => env.slug === environment)) {
// case: environment name [environment] is not a valid environment slug in workspace
throw Error('Failed to locate environment in workspace');
}
const serviceAccount = await ServiceAccount.findById(serviceAccountId);
if (!serviceAccount) {
// case: service account does not exist
throw ServiceAccountNotFoundError({ message: 'Failed to locate service account' });
}
const serviceAccountKey = await ServiceAccountKey.findOne({
serviceAccount: serviceAccount._id,
workspace: workspaceId
});
if (!serviceAccountKey) {
// case: service account key does not exist
throw ServiceAccountKeyNotFoundError({ message: 'Failed to locate service account key' });
}
} else {
throw new Error('Failed to validate workspace and environment for workspace-related permission');
}
}
}
const validateDeleteServiceAccountPermission = async ({
userId,
serviceAccountId,
name,
workspaceId,
environment
}: {
userId: Types.ObjectId;
serviceAccountId: Types.ObjectId;
name: string;
workspaceId: Types.ObjectId;
environment: string;
}) => {
// does the user have the authority to delete the permission?
// does the service account permission exist?
}
export {
validateCreateServiceAccountPermission
}