Add required endpoints/functions for service account to create service tokens

This commit is contained in:
Tuan Dang
2023-04-06 16:59:55 +03:00
parent a3b2d1c838
commit d54753289a
18 changed files with 431 additions and 220 deletions
+68 -17
View File
@@ -3,6 +3,7 @@ import { Types } from 'mongoose';
import {
IUser,
ISecret,
IServiceAccount,
User,
Membership
} from '../models';
@@ -11,8 +12,12 @@ import { validateMembership } from './membership';
import _ from 'lodash';
import { BadRequestError, UnauthorizedRequestError } from '../utils/errors';
import {
ABILITY_WRITE
} from '../variables/organization';
validateMembershipOrg
} from '../helpers/membershipOrg';
import {
PERMISSION_READ_SECRETS,
PERMISSION_WRITE_SECRETS
} from '../variables';
/**
* Initialize a user under email [email]
@@ -180,24 +185,38 @@ const validateUserClientForWorkspace = async ({
requiredPermissions?: string[];
}) => {
// org-level and workspace-level permissions? - workspace-level env scoped?
// validate user membership in workspace
const membership = await validateMembership({
userId: user._id,
workspaceId
});
// validate user permission
// TODO: validate that user can perform action on environment in workspace
// TODO: refactor
let runningIsDisallowed = false;
requiredPermissions?.forEach((requiredPermission: string) => {
switch (requiredPermission) {
case PERMISSION_READ_SECRETS:
runningIsDisallowed = _.some(membership.deniedPermissions, { environmentSlug: environment, ability: PERMISSION_READ_SECRETS });
break;
case PERMISSION_WRITE_SECRETS:
runningIsDisallowed = _.some(membership.deniedPermissions, { environmentSlug: environment, ability: PERMISSION_WRITE_SECRETS });
break;
default:
break;
}
if (runningIsDisallowed) {
throw UnauthorizedRequestError({
message: `Failed permissions authorization for workspace environment action : ${requiredPermission}`
});
}
});
return membership;
}
/**
* Validate that user (client) can access secrets with ids [secretIds]
* Validate that user (client) can access secrets [secrets]
* with required permissions [requiredPermissions]
* @param {Object} obj
* @param {User} obj.user - user client
@@ -213,7 +232,7 @@ const validateUserClientForWorkspace = async ({
secrets: ISecret[];
requiredPermissions?: string[];
}) => {
// TODO: consider refactor
// TODO: refactor
const userMemberships = await Membership.find({ user: user._id })
const userMembershipById = _.keyBy(userMemberships, 'workspace');
@@ -221,27 +240,59 @@ const validateUserClientForWorkspace = async ({
// for each secret check if the secret belongs to a workspace the user is a member of
secrets.forEach((secret: ISecret) => {
if (workspaceIdsSet.has(secret.workspace.toString())) {
if (!workspaceIdsSet.has(secret.workspace.toString())) {
throw BadRequestError({
message: 'Failed authorization for the secret'
});
}
if (requiredPermissions?.includes(PERMISSION_WRITE_SECRETS)) {
const deniedMembershipPermissions = userMembershipById[secret.workspace.toString()].deniedPermissions;
const isDisallowed = _.some(deniedMembershipPermissions, { environmentSlug: secret.environment, ability: ABILITY_WRITE });
const isDisallowed = _.some(deniedMembershipPermissions, { environmentSlug: secret.environment, ability: PERMISSION_WRITE_SECRETS });
if (isDisallowed) {
throw UnauthorizedRequestError({
message: 'You do not have the required permissions to perform this action'
});
}
} else {
throw BadRequestError({
message: 'You cannot edit secrets of a workspace you are not a member of'
});
}
});
}
/**
* Validate that user (client) can access service account [serviceAccount]
* with required permissions [requiredPermissions]
* @param {Object} obj
* @param {User} obj.user - user client
* @param {ServiceAccount} obj.serviceAccount - service account to validate against
* @param {String[]} requiredPermissions - required permissions as part of the endpoint
*/
const validateUserClientForServiceAccount = async ({
user,
serviceAccount,
requiredPermissions
}: {
user: IUser;
serviceAccount: IServiceAccount;
requiredPermissions?: string[];
}) => {
if (!serviceAccount.user.equals(user._id)) {
// case: user who created service account is not the
// same user that is on the request
await validateMembershipOrg({
userId: user._id,
organizationId: serviceAccount.organization,
acceptedRoles: [],
acceptedStatuses: []
});
}
}
export {
setupAccount,
completeAccount,
checkUserDevice,
validateUserClientForWorkspace,
validateUserClientForSecrets
validateUserClientForSecrets,
validateUserClientForServiceAccount
};