feat(secret-ref): removed migration field unset op, refactored service token scope check to a utility fn

This commit is contained in:
akhilmhdh
2023-07-06 20:01:46 +05:30
parent 5599132efe
commit 5aba0c60b8
4 changed files with 45 additions and 66 deletions
+13 -21
View File
@@ -1,6 +1,5 @@
import { Types } from "mongoose"; import { Types } from "mongoose";
import { Request, Response } from "express"; import { Request, Response } from "express";
import picomatch from "picomatch";
import { ISecret, Secret, ServiceTokenData } from "../../models"; import { ISecret, Secret, ServiceTokenData } from "../../models";
import { IAction, SecretVersion } from "../../ee/models"; import { IAction, SecretVersion } from "../../ee/models";
import { import {
@@ -33,6 +32,7 @@ import {
getFolderIdFromServiceToken, getFolderIdFromServiceToken,
searchByFolderId searchByFolderId
} from "../../services/FolderService"; } from "../../services/FolderService";
import { isValidScope } from "../../helpers/secrets";
/** /**
* Peform a batch of any specified CUD secret operations * Peform a batch of any specified CUD secret operations
@@ -74,16 +74,11 @@ export const batchSecrets = async (req: Request, res: Response) => {
} }
if (req.authData.authPayload instanceof ServiceTokenData) { if (req.authData.authPayload instanceof ServiceTokenData) {
const { scopes: tkScopes } = req.authData.authPayload; const isValidScopeAccess = isValidScope(req.authData.authPayload, environment, secretPath);
const validScope = tkScopes.find(
(scope) =>
picomatch.isMatch(secretPath, scope.secretPath, { strictSlashes: false }) &&
scope.environment === environment
);
// in service token when not giving secretpath folderid must be root // in service token when not giving secretpath folderid must be root
// this is to avoid giving folderid when service tokens are used // this is to avoid giving folderid when service tokens are used
if ((!secretPath && folderId !== "root") || (secretPath && !validScope)) { if ((!secretPath && folderId !== "root") || (secretPath && !isValidScopeAccess)) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
} }
} }
@@ -447,16 +442,15 @@ export const createSecrets = async (req: Request, res: Response) => {
} }
if (req.authData.authPayload instanceof ServiceTokenData) { if (req.authData.authPayload instanceof ServiceTokenData) {
const { scopes: tkScopes } = req.authData.authPayload; const isValidScopeAccess = isValidScope(
const validScope = tkScopes.find( req.authData.authPayload,
(scope) => environment,
picomatch.isMatch(secretPath || "/", scope.secretPath, { strictSlashes: false }) && secretPath || "/"
scope.environment === environment
); );
// in service token when not giving secretpath folderid must be root // in service token when not giving secretpath folderid must be root
// this is to avoid giving folderid when service tokens are used // this is to avoid giving folderid when service tokens are used
if ((!secretPath && folderId !== "root") || (secretPath && !validScope)) { if ((!secretPath && folderId !== "root") || (secretPath && !isValidScopeAccess)) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
} }
} }
@@ -704,17 +698,15 @@ export const getSecrets = async (req: Request, res: Response) => {
} }
if (req.authData.authPayload instanceof ServiceTokenData) { if (req.authData.authPayload instanceof ServiceTokenData) {
const { scopes: tkScopes } = req.authData.authPayload; const isValidScopeAccess = isValidScope(
const validScope = tkScopes.find( req.authData.authPayload,
(scope) => environment,
picomatch.isMatch((secretPath as string) || "/", scope.secretPath, { (secretPath as string) || "/"
strictSlashes: false
}) && scope.environment === environment
); );
// in service token when not giving secretpath folderid must be root // in service token when not giving secretpath folderid must be root
// this is to avoid giving folderid when service tokens are used // this is to avoid giving folderid when service tokens are used
if ((!secretPath && folderId !== "root") || (secretPath && !validScope)) { if ((!secretPath && folderId !== "root") || (secretPath && !isValidScopeAccess)) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
} }
} }
+27 -41
View File
@@ -6,7 +6,13 @@ import {
GetSecretsParams, GetSecretsParams,
UpdateSecretParams UpdateSecretParams
} from "../interfaces/services/SecretService"; } from "../interfaces/services/SecretService";
import { ISecret, Secret, SecretBlindIndexData, ServiceTokenData } from "../models"; import {
ISecret,
IServiceTokenData,
Secret,
SecretBlindIndexData,
ServiceTokenData
} from "../models";
import { SecretVersion } from "../ee/models"; import { SecretVersion } from "../ee/models";
import { import {
BadRequestError, BadRequestError,
@@ -39,6 +45,21 @@ import { getAuthDataPayloadIdObj, getAuthDataPayloadUserObj } from "../utils/aut
import { getFolderIdFromServiceToken } from "../services/FolderService"; import { getFolderIdFromServiceToken } from "../services/FolderService";
import picomatch from "picomatch"; import picomatch from "picomatch";
export const isValidScope = (
authPayload: IServiceTokenData,
environment: string,
secretPath: string
) => {
const { scopes: tkScopes } = authPayload;
const validScope = tkScopes.find(
(scope) =>
picomatch.isMatch(secretPath, scope.secretPath, { strictSlashes: false }) &&
scope.environment === environment
);
return Boolean(validScope);
};
/** /**
* Returns an object containing secret [secret] but with its value, key, comment decrypted. * Returns an object containing secret [secret] but with its value, key, comment decrypted.
* *
@@ -306,14 +327,7 @@ export const createSecretHelper = async ({
// 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 (authData.authPayload instanceof ServiceTokenData) {
const { scopes: tkScopes } = authData.authPayload; if (!isValidScope(authData.authPayload, environment, secretPath)) {
const validScope = tkScopes.find(
(scope) =>
picomatch.isMatch(secretPath, scope.secretPath, { strictSlashes: false }) &&
scope.environment === environment
);
if (!validScope) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
} }
} }
@@ -459,14 +473,7 @@ export const getSecretsHelper = async ({
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 (authData.authPayload instanceof ServiceTokenData) {
const { scopes: tkScopes } = authData.authPayload; if (!isValidScope(authData.authPayload, environment, secretPath)) {
const validScope = tkScopes.find(
(scope) =>
picomatch.isMatch(secretPath, scope.secretPath, { strictSlashes: false }) &&
scope.environment === environment
);
if (!validScope) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
} }
} }
@@ -562,14 +569,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 (authData.authPayload instanceof ServiceTokenData) {
const { scopes: tkScopes } = authData.authPayload; if (!isValidScope(authData.authPayload, environment, secretPath)) {
const validScope = tkScopes.find(
(scope) =>
picomatch.isMatch(secretPath, scope.secretPath, { strictSlashes: false }) &&
scope.environment === environment
);
if (!validScope) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
} }
} }
@@ -671,14 +671,7 @@ 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 using service token filter towards the folderId by secretpath
if (authData.authPayload instanceof ServiceTokenData) { if (authData.authPayload instanceof ServiceTokenData) {
const { scopes: tkScopes } = authData.authPayload; if (!isValidScope(authData.authPayload, environment, secretPath)) {
const validScope = tkScopes.find(
(scope) =>
picomatch.isMatch(secretPath, scope.secretPath, { strictSlashes: false }) &&
scope.environment === environment
);
if (!validScope) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
} }
} }
@@ -826,14 +819,7 @@ export const deleteSecretHelper = async ({
// 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 (authData.authPayload instanceof ServiceTokenData) {
const { scopes: tkScopes } = authData.authPayload; if (!isValidScope(authData.authPayload, environment, secretPath)) {
const validScope = tkScopes.find(
(scope) =>
picomatch.isMatch(secretPath, scope.secretPath, { strictSlashes: false }) &&
scope.environment === environment
);
if (!validScope) {
throw UnauthorizedRequestError({ message: "Folder Permission Denied" }); throw UnauthorizedRequestError({ message: "Folder Permission Denied" });
} }
} }
-3
View File
@@ -446,9 +446,6 @@ export const backfillServiceTokenMultiScope = async () => {
$set: { $set: {
scopes: [{ environment: "$environment", secretPath: "$secretPath" }] scopes: [{ environment: "$environment", secretPath: "$secretPath" }]
} }
},
{
$unset: ["environment", "secretPath"]
} }
] ]
); );
+5 -1
View File
@@ -292,7 +292,11 @@ func recursivelyExpandSecret(expandedSecs map[string]string, interpolatedSecs ma
return v return v
} }
interpolatedVal := interpolatedSecs[key] interpolatedVal, ok := interpolatedSecs[key]
if !ok {
HandleError(fmt.Errorf("Could not find refered secret - %s", key), "Kindly check whether its provided")
}
refs := secRefRegex.FindAllStringSubmatch(interpolatedVal, -1) refs := secRefRegex.FindAllStringSubmatch(interpolatedVal, -1)
for _, val := range refs { for _, val := range refs {
// key: "${something}" val: [${something},something] // key: "${something}" val: [${something},something]