feat(rbac): made new permission check for v3 secrets and v2 batch

This commit is contained in:
Akhil Mohan
2023-08-29 20:14:24 +05:30
parent 82d4c8f000
commit bcfe1bda84
6 changed files with 150 additions and 137 deletions

View File

@@ -35,7 +35,17 @@ import { isValidScope } from "../../helpers/secrets";
import path from "path"; import path from "path";
import { getAllImportedSecrets } from "../../services/SecretImportService"; import { getAllImportedSecrets } from "../../services/SecretImportService";
import { validateRequest } from "../../helpers/validation"; import { validateRequest } from "../../helpers/validation";
import { BatchSecretsV2, GetSecretsV2 } from "../../validation"; import {
BatchSecretsV2,
GetSecretsV2,
validateServiceTokenDataClientForWorkspace
} from "../../validation";
import {
ProjectPermissionActions,
ProjectPermissionSub,
getUserProjectPermissions
} from "../../services/ProjectRoleService";
import { ForbiddenError, subject } from "@casl/ability";
/** /**
* Peform a batch of any specified CUD secret operations * Peform a batch of any specified CUD secret operations
@@ -68,17 +78,13 @@ export const batchSecrets = async (req: Request, res: Response) => {
const folders = await Folder.findOne({ workspace: workspaceId, environment }); const folders = await Folder.findOne({ workspace: workspaceId, environment });
if (req.authData.authPayload instanceof ServiceTokenData) { if (req.authData.authPayload instanceof ServiceTokenData) {
const isValidScopeAccess = isValidScope( await validateServiceTokenDataClientForWorkspace({
req.authData.authPayload, serviceTokenData: req.authData.authPayload,
workspaceId: new Types.ObjectId(workspaceId),
environment, environment,
secretPath || "/" secretPath,
); requiredPermissions: [PERMISSION_WRITE_SECRETS]
});
// in service token when not giving secretpath folderid must be root
// this is to avoid giving folderid when service tokens are used
if ((!secretPath && folderId !== "root") || (secretPath && !isValidScopeAccess)) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
}
} }
if (secretPath) { if (secretPath) {
@@ -94,6 +100,22 @@ export const batchSecrets = async (req: Request, res: Response) => {
); );
} }
if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath })
);
}
for await (const request of requests) { for await (const request of requests) {
// do a validation // do a validation
@@ -977,17 +999,17 @@ export const getSecrets = async (req: Request, res: Response) => {
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
// reduce the number of events captured // reduce the number of events captured
let shouldRecordK8Event = false let shouldRecordK8Event = false;
if (req.authData.userAgent == K8_USER_AGENT_NAME) { if (req.authData.userAgent == K8_USER_AGENT_NAME) {
const randomNumber = Math.random(); const randomNumber = Math.random();
if (randomNumber > 0.9) { if (randomNumber > 0.9) {
shouldRecordK8Event = true shouldRecordK8Event = true;
} }
} }
if (postHogClient) { if (postHogClient) {
const shouldCapture = req.authData.userAgent !== K8_USER_AGENT_NAME || shouldRecordK8Event; const shouldCapture = req.authData.userAgent !== K8_USER_AGENT_NAME || shouldRecordK8Event;
const approximateForNoneCapturedEvents = secrets.length * 10 const approximateForNoneCapturedEvents = secrets.length * 10;
if (shouldCapture) { if (shouldCapture) {
postHogClient.capture({ postHogClient.capture({
@@ -1111,10 +1133,10 @@ export const updateSecrets = async (req: Request, res: Response) => {
tags, tags,
...(secretCommentCiphertext !== undefined && secretCommentIV && secretCommentTag ...(secretCommentCiphertext !== undefined && secretCommentIV && secretCommentTag
? { ? {
secretCommentCiphertext, secretCommentCiphertext,
secretCommentIV, secretCommentIV,
secretCommentTag secretCommentTag
} }
: {}) : {})
} }
} }

View File

@@ -17,6 +17,8 @@ import {
getUserProjectPermissions getUserProjectPermissions
} from "../../services/ProjectRoleService"; } from "../../services/ProjectRoleService";
import { ForbiddenError, subject } from "@casl/ability"; import { ForbiddenError, subject } from "@casl/ability";
import { validateServiceTokenDataClientForWorkspace } from "../../validation";
import { PERMISSION_READ_SECRETS, PERMISSION_WRITE_SECRETS } from "../../variables";
/** /**
* Return secrets for workspace with id [workspaceId] and environment * Return secrets for workspace with id [workspaceId] and environment
@@ -40,12 +42,22 @@ export const getSecretsRaw = async (req: Request, res: Response) => {
secretPath = scope.secretPath; secretPath = scope.secretPath;
environment = scope.environment; environment = scope.environment;
workspaceId = serviceTokenDetails.workspace.toString(); workspaceId = serviceTokenDetails.workspace.toString();
} else { }
if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read, ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_READ_SECRETS]
});
} }
const secrets = await SecretService.getSecrets({ const secrets = await SecretService.getSecrets({
@@ -108,12 +120,20 @@ export const getSecretByNameRaw = async (req: Request, res: Response) => {
params: { secretName } params: { secretName }
} = await validateRequest(reqValidator.GetSecretByNameRawV3, req); } = await validateRequest(reqValidator.GetSecretByNameRawV3, req);
if (req.user._id) { if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read, ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_READ_SECRETS]
});
} }
const secret = await SecretService.getSecret({ const secret = await SecretService.getSecret({
@@ -148,12 +168,20 @@ export const createSecretRaw = async (req: Request, res: Response) => {
body: { secretPath, environment, workspaceId, type, secretValue, secretComment } body: { secretPath, environment, workspaceId, type, secretValue, secretComment }
} = await validateRequest(reqValidator.CreateSecretRawV3, req); } = await validateRequest(reqValidator.CreateSecretRawV3, req);
if (req.user._id) { if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create, ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_WRITE_SECRETS]
});
} }
const key = await BotService.getWorkspaceKeyWithBot({ const key = await BotService.getWorkspaceKeyWithBot({
@@ -223,12 +251,20 @@ export const updateSecretByNameRaw = async (req: Request, res: Response) => {
body: { secretValue, environment, secretPath, type, workspaceId } body: { secretValue, environment, secretPath, type, workspaceId }
} = await validateRequest(reqValidator.UpdateSecretByNameRawV3, req); } = await validateRequest(reqValidator.UpdateSecretByNameRawV3, req);
if (req.user._id) { if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit, ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_WRITE_SECRETS]
});
} }
const key = await BotService.getWorkspaceKeyWithBot({ const key = await BotService.getWorkspaceKeyWithBot({
@@ -279,12 +315,20 @@ export const deleteSecretByNameRaw = async (req: Request, res: Response) => {
body: { environment, secretPath, type, workspaceId } body: { environment, secretPath, type, workspaceId }
} = await validateRequest(reqValidator.DeleteSecretByNameRawV3, req); } = await validateRequest(reqValidator.DeleteSecretByNameRawV3, req);
if (req.user._id) { if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete, ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_WRITE_SECRETS]
});
} }
const { secret } = await SecretService.deleteSecret({ const { secret } = await SecretService.deleteSecret({
@@ -327,12 +371,20 @@ export const getSecrets = async (req: Request, res: Response) => {
query: { secretPath, environment, workspaceId, include_imports: includeImports,folderId } query: { secretPath, environment, workspaceId, include_imports: includeImports,folderId }
} = await validateRequest(reqValidator.GetSecretsV3, req); } = await validateRequest(reqValidator.GetSecretsV3, req);
if (req.user._id) { if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read, ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_READ_SECRETS]
});
} }
const secrets = await SecretService.getSecrets({ const secrets = await SecretService.getSecrets({
@@ -377,12 +429,20 @@ export const getSecretByName = async (req: Request, res: Response) => {
params: { secretName } params: { secretName }
} = await validateRequest(reqValidator.GetSecretByNameV3, req); } = await validateRequest(reqValidator.GetSecretByNameV3, req);
if (req.user._id) { if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Read, ProjectPermissionActions.Read,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_READ_SECRETS]
});
} }
const secret = await SecretService.getSecret({ const secret = await SecretService.getSecret({
@@ -425,12 +485,20 @@ export const createSecret = async (req: Request, res: Response) => {
} }
} = await validateRequest(reqValidator.CreateSecretV3, req); } = await validateRequest(reqValidator.CreateSecretV3, req);
if (req.user._id) { if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Create, ProjectPermissionActions.Create,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_WRITE_SECRETS]
});
} }
const secret = await SecretService.createSecret({ const secret = await SecretService.createSecret({
@@ -487,12 +555,20 @@ export const updateSecretByName = async (req: Request, res: Response) => {
params: { secretName } params: { secretName }
} = await validateRequest(reqValidator.UpdateSecretByNameV3, req); } = await validateRequest(reqValidator.UpdateSecretByNameV3, req);
if (req.user._id) { if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Edit, ProjectPermissionActions.Edit,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_WRITE_SECRETS]
});
} }
const secret = await SecretService.updateSecret({ const secret = await SecretService.updateSecret({
@@ -531,12 +607,20 @@ export const deleteSecretByName = async (req: Request, res: Response) => {
params: { secretName } params: { secretName }
} = await validateRequest(reqValidator.DeleteSecretByNameV3, req); } = await validateRequest(reqValidator.DeleteSecretByNameV3, req);
if (req.user._id) { if (req.user?._id) {
const { permission } = await getUserProjectPermissions(req.user._id, workspaceId); const { permission } = await getUserProjectPermissions(req.user._id, workspaceId);
ForbiddenError.from(permission).throwUnlessCan( ForbiddenError.from(permission).throwUnlessCan(
ProjectPermissionActions.Delete, ProjectPermissionActions.Delete,
subject(ProjectPermissionSub.Secrets, { environment, secretPath }) subject(ProjectPermissionSub.Secrets, { environment, secretPath })
); );
} else {
await validateServiceTokenDataClientForWorkspace({
serviceTokenData: req.authData.authPayload as IServiceTokenData,
workspaceId: new Types.ObjectId(workspaceId),
environment,
secretPath,
requiredPermissions: [PERMISSION_WRITE_SECRETS]
});
} }
const { secret } = await SecretService.deleteSecret({ const { secret } = await SecretService.deleteSecret({

View File

@@ -504,11 +504,6 @@ export const getSecretsHelper = async ({
}: GetSecretsParams) => { }: GetSecretsParams) => {
let secrets: ISecret[] = []; let secrets: ISecret[] = [];
// if using service token filter towards the folderId by secretpath // if using service token filter towards the folderId by secretpath
if (authData.authPayload instanceof ServiceTokenData) {
if (!isValidScope(authData.authPayload, environment, secretPath)) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
}
}
if (!folderId) { if (!folderId) {
folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath); folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
@@ -575,11 +570,11 @@ export const getSecretsHelper = async ({
const postHogClient = await TelemetryService.getPostHogClient(); const postHogClient = await TelemetryService.getPostHogClient();
// reduce the number of events captured // reduce the number of events captured
let shouldRecordK8Event = false let shouldRecordK8Event = false;
if (authData.userAgent == K8_USER_AGENT_NAME) { if (authData.userAgent == K8_USER_AGENT_NAME) {
const randomNumber = Math.random(); const randomNumber = Math.random();
if (randomNumber > 0.9) { if (randomNumber > 0.9) {
shouldRecordK8Event = true shouldRecordK8Event = true;
} }
} }
@@ -588,7 +583,7 @@ export const getSecretsHelper = async ({
if (postHogClient && atLeastOneNonSignUpSecret) { if (postHogClient && atLeastOneNonSignUpSecret) {
const shouldCapture = authData.userAgent !== K8_USER_AGENT_NAME || shouldRecordK8Event; const shouldCapture = authData.userAgent !== K8_USER_AGENT_NAME || shouldRecordK8Event;
const approximateForNoneCapturedEvents = secrets.length * 10 const approximateForNoneCapturedEvents = secrets.length * 10;
if (shouldCapture) { if (shouldCapture) {
postHogClient.capture({ postHogClient.capture({
@@ -633,11 +628,7 @@ export const getSecretHelper = async ({
}); });
let secret: ISecret | null = null; let secret: ISecret | null = null;
// if using service token filter towards the folderId by secretpath // if using service token filter towards the folderId by secretpath
if (authData.authPayload instanceof ServiceTokenData) {
if (!isValidScope(authData.authPayload, environment, secretPath)) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
}
}
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath); const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
// try getting personal secret first (if exists) // try getting personal secret first (if exists)
@@ -751,12 +742,6 @@ export const updateSecretHelper = async ({
}); });
let secret: ISecret | null = null; let secret: ISecret | null = null;
// if using service token filter towards the folderId by secretpath
if (authData.authPayload instanceof ServiceTokenData) {
if (!isValidScope(authData.authPayload, environment, secretPath)) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
}
}
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath); const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
if (type === SECRET_SHARED) { if (type === SECRET_SHARED) {
@@ -916,12 +901,6 @@ export const deleteSecretHelper = async ({
workspaceId: new Types.ObjectId(workspaceId) workspaceId: new Types.ObjectId(workspaceId)
}); });
// if using service token filter towards the folderId by secretpath
if (authData.authPayload instanceof ServiceTokenData) {
if (!isValidScope(authData.authPayload, environment, secretPath)) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
}
}
const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath); const folderId = await getFolderIdFromServiceToken(workspaceId, environment, secretPath);
let secrets: ISecret[] = []; let secrets: ISecret[] = [];

View File

@@ -24,10 +24,6 @@ router.post(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body"
}),
secretsController.batchSecrets secretsController.batchSecrets
); );

View File

@@ -1,22 +1,13 @@
import express from "express"; import express from "express";
const router = express.Router(); const router = express.Router();
import { import {
requireAuth, requireAuth,
requireBlindIndicesEnabled, requireBlindIndicesEnabled,
requireE2EEOff, requireE2EEOff
requireWorkspaceAuth,
validateRequest
} from "../../middleware"; } from "../../middleware";
import { body, param, query } from "express-validator";
import { secretsController } from "../../controllers/v3"; import { secretsController } from "../../controllers/v3";
import { import {
ADMIN, AuthMode
AuthMode,
MEMBER,
PERMISSION_READ_SECRETS,
PERMISSION_WRITE_SECRETS,
SECRET_PERSONAL,
SECRET_SHARED
} from "../../variables"; } from "../../variables";
router.get( router.get(
@@ -32,12 +23,6 @@ router.get(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "query",
locationEnvironment: "query",
requiredPermissions: [PERMISSION_READ_SECRETS]
}),
requireBlindIndicesEnabled({ requireBlindIndicesEnabled({
locationWorkspaceId: "query" locationWorkspaceId: "query"
}), }),
@@ -52,12 +37,6 @@ router.post(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS]
}),
requireBlindIndicesEnabled({ requireBlindIndicesEnabled({
locationWorkspaceId: "body" locationWorkspaceId: "body"
}), }),
@@ -72,12 +51,6 @@ router.patch(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS]
}),
requireBlindIndicesEnabled({ requireBlindIndicesEnabled({
locationWorkspaceId: "body" locationWorkspaceId: "body"
}), }),
@@ -92,12 +65,6 @@ router.delete(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS]
}),
requireBlindIndicesEnabled({ requireBlindIndicesEnabled({
locationWorkspaceId: "body" locationWorkspaceId: "body"
}), }),
@@ -109,20 +76,9 @@ router.delete(
router.get( router.get(
"/", "/",
query("workspaceId").exists().isString().trim(),
query("environment").exists().isString().trim(),
query("folderId").optional().isString().trim(),
query("secretPath").default("/").isString().trim(),
validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "query",
locationEnvironment: "query",
requiredPermissions: [PERMISSION_READ_SECRETS]
}),
requireBlindIndicesEnabled({ requireBlindIndicesEnabled({
locationWorkspaceId: "query" locationWorkspaceId: "query"
}), }),
@@ -134,12 +90,6 @@ router.post(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS]
}),
requireBlindIndicesEnabled({ requireBlindIndicesEnabled({
locationWorkspaceId: "body" locationWorkspaceId: "body"
}), }),
@@ -151,12 +101,6 @@ router.get(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "query",
locationEnvironment: "query",
requiredPermissions: [PERMISSION_READ_SECRETS]
}),
requireBlindIndicesEnabled({ requireBlindIndicesEnabled({
locationWorkspaceId: "query" locationWorkspaceId: "query"
}), }),
@@ -168,12 +112,6 @@ router.patch(
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS]
}),
requireBlindIndicesEnabled({ requireBlindIndicesEnabled({
locationWorkspaceId: "body" locationWorkspaceId: "body"
}), }),
@@ -182,21 +120,9 @@ router.patch(
router.delete( router.delete(
"/:secretName", "/:secretName",
param("secretName").exists().isString().trim(),
body("workspaceId").exists().isString().trim(),
body("environment").exists().isString().trim(),
body("secretPath").default("/").isString().trim(),
body("type").exists().isIn([SECRET_SHARED, SECRET_PERSONAL]),
validateRequest,
requireAuth({ requireAuth({
acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN] acceptedAuthModes: [AuthMode.JWT, AuthMode.API_KEY, AuthMode.SERVICE_TOKEN]
}), }),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "body",
locationEnvironment: "body",
requiredPermissions: [PERMISSION_WRITE_SECRETS]
}),
requireBlindIndicesEnabled({ requireBlindIndicesEnabled({
locationWorkspaceId: "body" locationWorkspaceId: "body"
}), }),

View File

@@ -5,6 +5,7 @@ import { validateUserClientForWorkspace } from "./user";
import { ActorType } from "../ee/models"; import { ActorType } from "../ee/models";
import { AuthData } from "../interfaces/middleware"; import { AuthData } from "../interfaces/middleware";
import { z } from "zod"; import { z } from "zod";
import { isValidScope } from "../helpers";
/** /**
* Validate authenticated clients for service token with id [serviceTokenId] based * Validate authenticated clients for service token with id [serviceTokenId] based
@@ -62,11 +63,13 @@ export const validateServiceTokenDataClientForWorkspace = async ({
serviceTokenData, serviceTokenData,
workspaceId, workspaceId,
environment, environment,
secretPath = "/",
requiredPermissions requiredPermissions
}: { }: {
serviceTokenData: IServiceTokenData; serviceTokenData: IServiceTokenData;
workspaceId: Types.ObjectId; workspaceId: Types.ObjectId;
environment?: string; environment?: string;
secretPath?: string;
requiredPermissions?: string[]; requiredPermissions?: string[];
}) => { }) => {
if (!serviceTokenData.workspace.equals(workspaceId)) { if (!serviceTokenData.workspace.equals(workspaceId)) {
@@ -78,7 +81,6 @@ export const validateServiceTokenDataClientForWorkspace = async ({
if (environment) { if (environment) {
// case: environment is specified // case: environment is specified
if (!serviceTokenData.scopes.find(({ environment: tkEnv }) => tkEnv === environment)) { if (!serviceTokenData.scopes.find(({ environment: tkEnv }) => tkEnv === environment)) {
// case: invalid environment passed // case: invalid environment passed
throw UnauthorizedRequestError({ throw UnauthorizedRequestError({
@@ -86,6 +88,10 @@ export const validateServiceTokenDataClientForWorkspace = async ({
}); });
} }
if (!isValidScope(serviceTokenData, environment, secretPath)) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
}
requiredPermissions?.forEach((permission) => { requiredPermissions?.forEach((permission) => {
if (!serviceTokenData.permissions.includes(permission)) { if (!serviceTokenData.permissions.includes(permission)) {
throw UnauthorizedRequestError({ throw UnauthorizedRequestError({