mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-06 20:27:12 +00:00
grant permissions
This commit is contained in:
@@ -4,6 +4,7 @@ import {
|
|||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionAppConnectionActions,
|
ProjectPermissionAppConnectionActions,
|
||||||
ProjectPermissionApprovalRequestActions,
|
ProjectPermissionApprovalRequestActions,
|
||||||
|
ProjectPermissionApprovalRequestGrantActions,
|
||||||
ProjectPermissionAuditLogsActions,
|
ProjectPermissionAuditLogsActions,
|
||||||
ProjectPermissionCertificateActions,
|
ProjectPermissionCertificateActions,
|
||||||
ProjectPermissionCertificateAuthorityActions,
|
ProjectPermissionCertificateAuthorityActions,
|
||||||
@@ -345,6 +346,11 @@ const buildAdminPermissionRules = () => {
|
|||||||
ProjectPermissionSub.ApprovalRequests
|
ProjectPermissionSub.ApprovalRequests
|
||||||
);
|
);
|
||||||
|
|
||||||
|
can(
|
||||||
|
[ProjectPermissionApprovalRequestGrantActions.Read, ProjectPermissionApprovalRequestGrantActions.Revoke],
|
||||||
|
ProjectPermissionSub.ApprovalRequestGrants
|
||||||
|
);
|
||||||
|
|
||||||
return rules;
|
return rules;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -229,6 +229,11 @@ export enum ProjectPermissionApprovalRequestActions {
|
|||||||
Create = "create"
|
Create = "create"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ProjectPermissionApprovalRequestGrantActions {
|
||||||
|
Read = "read",
|
||||||
|
Revoke = "revoke"
|
||||||
|
}
|
||||||
|
|
||||||
export const isCustomProjectRole = (slug: string) =>
|
export const isCustomProjectRole = (slug: string) =>
|
||||||
!Object.values(ProjectMembershipRole).includes(slug as ProjectMembershipRole);
|
!Object.values(ProjectMembershipRole).includes(slug as ProjectMembershipRole);
|
||||||
|
|
||||||
@@ -280,7 +285,8 @@ export enum ProjectPermissionSub {
|
|||||||
PamAccounts = "pam-accounts",
|
PamAccounts = "pam-accounts",
|
||||||
PamSessions = "pam-sessions",
|
PamSessions = "pam-sessions",
|
||||||
CertificateProfiles = "certificate-profiles",
|
CertificateProfiles = "certificate-profiles",
|
||||||
ApprovalRequests = "approval-requests"
|
ApprovalRequests = "approval-requests",
|
||||||
|
ApprovalRequestGrants = "approval-request-grants"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SecretSubjectFields = {
|
export type SecretSubjectFields = {
|
||||||
@@ -507,7 +513,8 @@ export type ProjectPermissionSet =
|
|||||||
| (ForcedSubject<ProjectPermissionSub.CertificateProfiles> & CertificateProfileSubjectFields)
|
| (ForcedSubject<ProjectPermissionSub.CertificateProfiles> & CertificateProfileSubjectFields)
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
| [ProjectPermissionApprovalRequestActions, ProjectPermissionSub.ApprovalRequests];
|
| [ProjectPermissionApprovalRequestActions, ProjectPermissionSub.ApprovalRequests]
|
||||||
|
| [ProjectPermissionApprovalRequestGrantActions, ProjectPermissionSub.ApprovalRequestGrants];
|
||||||
|
|
||||||
const SECRET_PATH_MISSING_SLASH_ERR_MSG = "Invalid Secret Path; it must start with a '/'";
|
const SECRET_PATH_MISSING_SLASH_ERR_MSG = "Invalid Secret Path; it must start with a '/'";
|
||||||
const SECRET_PATH_PERMISSION_OPERATOR_SCHEMA = z.union([
|
const SECRET_PATH_PERMISSION_OPERATOR_SCHEMA = z.union([
|
||||||
@@ -1118,6 +1125,12 @@ const GeneralPermissionSchema = [
|
|||||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionApprovalRequestActions).describe(
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionApprovalRequestActions).describe(
|
||||||
"Describe what action an entity can take."
|
"Describe what action an entity can take."
|
||||||
)
|
)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z.literal(ProjectPermissionSub.ApprovalRequestGrants).describe("The entity this permission pertains to."),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(ProjectPermissionApprovalRequestGrantActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import {
|
import {
|
||||||
ProjectPermissionActions,
|
ProjectPermissionActions,
|
||||||
ProjectPermissionApprovalRequestActions,
|
ProjectPermissionApprovalRequestActions,
|
||||||
|
ProjectPermissionApprovalRequestGrantActions,
|
||||||
ProjectPermissionSub
|
ProjectPermissionSub
|
||||||
} from "@app/ee/services/permission/project-permission";
|
} from "@app/ee/services/permission/project-permission";
|
||||||
|
|
||||||
@@ -87,7 +88,7 @@ export const approvalPolicyServiceFactory = ({
|
|||||||
|
|
||||||
if (userIdsToNotify.size === 0) return;
|
if (userIdsToNotify.size === 0) return;
|
||||||
|
|
||||||
// TODO: Potentially link to requests in the future?
|
// TODO: Potentially link to requests in the future to support click redirects
|
||||||
await notificationService.createUserNotifications(
|
await notificationService.createUserNotifications(
|
||||||
Array.from(userIdsToNotify).map((userId) => ({
|
Array.from(userIdsToNotify).map((userId) => ({
|
||||||
userId,
|
userId,
|
||||||
@@ -793,20 +794,44 @@ export const approvalPolicyServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const listGrants = async (policyType: ApprovalPolicyType, projectId: string, actor: OrgServiceActor) => {
|
const listGrants = async (policyType: ApprovalPolicyType, projectId: string, actor: OrgServiceActor) => {
|
||||||
// TODO(andrey): Perm check
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
|
actor: actor.type,
|
||||||
|
actorAuthMethod: actor.authMethod,
|
||||||
|
actorId: actor.id,
|
||||||
|
actorOrgId: actor.orgId,
|
||||||
|
projectId,
|
||||||
|
actionProjectType: ActionProjectType.Any
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionApprovalRequestGrantActions.Read,
|
||||||
|
ProjectPermissionSub.ApprovalRequestGrants
|
||||||
|
);
|
||||||
|
|
||||||
const grants = await approvalRequestGrantsDAL.find({ projectId, type: policyType });
|
const grants = await approvalRequestGrantsDAL.find({ projectId, type: policyType });
|
||||||
return { grants };
|
return { grants };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getGrantById = async (grantId: string, actor: OrgServiceActor) => {
|
const getGrantById = async (grantId: string, actor: OrgServiceActor) => {
|
||||||
// TODO(andrey): Perm check
|
|
||||||
|
|
||||||
const grant = await approvalRequestGrantsDAL.findById(grantId);
|
const grant = await approvalRequestGrantsDAL.findById(grantId);
|
||||||
if (!grant) {
|
if (!grant) {
|
||||||
throw new NotFoundError({ message: "Grant not found" });
|
throw new NotFoundError({ message: "Grant not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
|
actor: actor.type,
|
||||||
|
actorAuthMethod: actor.authMethod,
|
||||||
|
actorId: actor.id,
|
||||||
|
actorOrgId: actor.orgId,
|
||||||
|
projectId: grant.projectId,
|
||||||
|
actionProjectType: ActionProjectType.Any
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionApprovalRequestGrantActions.Read,
|
||||||
|
ProjectPermissionSub.ApprovalRequestGrants
|
||||||
|
);
|
||||||
|
|
||||||
return { grant };
|
return { grant };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -815,13 +840,25 @@ export const approvalPolicyServiceFactory = ({
|
|||||||
{ revocationReason }: { revocationReason?: string },
|
{ revocationReason }: { revocationReason?: string },
|
||||||
actor: OrgServiceActor
|
actor: OrgServiceActor
|
||||||
) => {
|
) => {
|
||||||
// TODO(andrey): Perm check
|
|
||||||
|
|
||||||
const grant = await approvalRequestGrantsDAL.findById(grantId);
|
const grant = await approvalRequestGrantsDAL.findById(grantId);
|
||||||
if (!grant) {
|
if (!grant) {
|
||||||
throw new NotFoundError({ message: "Grant not found" });
|
throw new NotFoundError({ message: "Grant not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
|
actor: actor.type,
|
||||||
|
actorAuthMethod: actor.authMethod,
|
||||||
|
actorId: actor.id,
|
||||||
|
actorOrgId: actor.orgId,
|
||||||
|
projectId: grant.projectId,
|
||||||
|
actionProjectType: ActionProjectType.Any
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
ProjectPermissionApprovalRequestGrantActions.Revoke,
|
||||||
|
ProjectPermissionSub.ApprovalRequestGrants
|
||||||
|
);
|
||||||
|
|
||||||
if (grant.status !== ApprovalRequestGrantStatus.Active) {
|
if (grant.status !== ApprovalRequestGrantStatus.Active) {
|
||||||
throw new BadRequestError({ message: "Grant is not active" });
|
throw new BadRequestError({ message: "Grant is not active" });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -233,6 +233,11 @@ export enum ProjectPermissionApprovalRequestActions {
|
|||||||
Create = "create"
|
Create = "create"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum ProjectPermissionApprovalRequestGrantActions {
|
||||||
|
Read = "read",
|
||||||
|
Revoke = "revoke"
|
||||||
|
}
|
||||||
|
|
||||||
export type IdentityManagementSubjectFields = {
|
export type IdentityManagementSubjectFields = {
|
||||||
identityId: string;
|
identityId: string;
|
||||||
};
|
};
|
||||||
@@ -345,7 +350,8 @@ export enum ProjectPermissionSub {
|
|||||||
PamResources = "pam-resources",
|
PamResources = "pam-resources",
|
||||||
PamAccounts = "pam-accounts",
|
PamAccounts = "pam-accounts",
|
||||||
PamSessions = "pam-sessions",
|
PamSessions = "pam-sessions",
|
||||||
ApprovalRequests = "approval-requests"
|
ApprovalRequests = "approval-requests",
|
||||||
|
ApprovalRequestGrants = "approval-request-grants"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SecretSubjectFields = {
|
export type SecretSubjectFields = {
|
||||||
@@ -584,6 +590,7 @@ export type ProjectPermissionSet =
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
| [ProjectPermissionPamSessionActions, ProjectPermissionSub.PamSessions]
|
| [ProjectPermissionPamSessionActions, ProjectPermissionSub.PamSessions]
|
||||||
| [ProjectPermissionApprovalRequestActions, ProjectPermissionSub.ApprovalRequests];
|
| [ProjectPermissionApprovalRequestActions, ProjectPermissionSub.ApprovalRequests]
|
||||||
|
| [ProjectPermissionApprovalRequestGrantActions, ProjectPermissionSub.ApprovalRequestGrants];
|
||||||
|
|
||||||
export type TProjectPermission = MongoAbility<ProjectPermissionSet>;
|
export type TProjectPermission = MongoAbility<ProjectPermissionSet>;
|
||||||
|
|||||||
+31
-2
@@ -16,6 +16,7 @@ import {
|
|||||||
PermissionConditionOperators,
|
PermissionConditionOperators,
|
||||||
ProjectPermissionAppConnectionActions,
|
ProjectPermissionAppConnectionActions,
|
||||||
ProjectPermissionApprovalRequestActions,
|
ProjectPermissionApprovalRequestActions,
|
||||||
|
ProjectPermissionApprovalRequestGrantActions,
|
||||||
ProjectPermissionAuditLogsActions,
|
ProjectPermissionAuditLogsActions,
|
||||||
ProjectPermissionCommitsActions,
|
ProjectPermissionCommitsActions,
|
||||||
ProjectPermissionDynamicSecretActions,
|
ProjectPermissionDynamicSecretActions,
|
||||||
@@ -264,6 +265,11 @@ const ApprovalRequestPolicyActionSchema = z.object({
|
|||||||
[ProjectPermissionApprovalRequestActions.Create]: z.boolean().optional()
|
[ProjectPermissionApprovalRequestActions.Create]: z.boolean().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const ApprovalRequestGrantPolicyActionSchema = z.object({
|
||||||
|
[ProjectPermissionApprovalRequestGrantActions.Read]: z.boolean().optional(),
|
||||||
|
[ProjectPermissionApprovalRequestGrantActions.Revoke]: z.boolean().optional()
|
||||||
|
});
|
||||||
|
|
||||||
const SecretRollbackPolicyActionSchema = z.object({
|
const SecretRollbackPolicyActionSchema = z.object({
|
||||||
read: z.boolean().optional(),
|
read: z.boolean().optional(),
|
||||||
create: z.boolean().optional()
|
create: z.boolean().optional()
|
||||||
@@ -475,7 +481,11 @@ export const projectRoleFormSchema = z.object({
|
|||||||
.array()
|
.array()
|
||||||
.default([]),
|
.default([]),
|
||||||
[ProjectPermissionSub.PamSessions]: PamSessionPolicyActionSchema.array().default([]),
|
[ProjectPermissionSub.PamSessions]: PamSessionPolicyActionSchema.array().default([]),
|
||||||
[ProjectPermissionSub.ApprovalRequests]: ApprovalRequestPolicyActionSchema.array().default([])
|
[ProjectPermissionSub.ApprovalRequests]: ApprovalRequestPolicyActionSchema.array().default(
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
[ProjectPermissionSub.ApprovalRequestGrants]:
|
||||||
|
ApprovalRequestGrantPolicyActionSchema.array().default([])
|
||||||
})
|
})
|
||||||
.partial()
|
.partial()
|
||||||
.optional()
|
.optional()
|
||||||
@@ -1306,6 +1316,17 @@ export const rolePermission2Form = (permissions: TProjectPermission[] = []) => {
|
|||||||
if (canRead) formVal[subject]![0][ProjectPermissionApprovalRequestActions.Read] = true;
|
if (canRead) formVal[subject]![0][ProjectPermissionApprovalRequestActions.Read] = true;
|
||||||
if (canCreate) formVal[subject]![0][ProjectPermissionApprovalRequestActions.Create] = true;
|
if (canCreate) formVal[subject]![0][ProjectPermissionApprovalRequestActions.Create] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (subject === ProjectPermissionSub.ApprovalRequestGrants) {
|
||||||
|
const canRead = action.includes(ProjectPermissionApprovalRequestGrantActions.Read);
|
||||||
|
const canRevoke = action.includes(ProjectPermissionApprovalRequestGrantActions.Revoke);
|
||||||
|
|
||||||
|
if (!formVal[subject]) formVal[subject] = [{}];
|
||||||
|
|
||||||
|
if (canRead) formVal[subject]![0][ProjectPermissionApprovalRequestGrantActions.Read] = true;
|
||||||
|
if (canRevoke)
|
||||||
|
formVal[subject]![0][ProjectPermissionApprovalRequestGrantActions.Revoke] = true;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return formVal;
|
return formVal;
|
||||||
@@ -1982,6 +2003,13 @@ export const PROJECT_PERMISSION_OBJECT: TProjectPermissionObject = {
|
|||||||
{ label: "Read", value: ProjectPermissionApprovalRequestActions.Read },
|
{ label: "Read", value: ProjectPermissionApprovalRequestActions.Read },
|
||||||
{ label: "Create", value: ProjectPermissionApprovalRequestActions.Create }
|
{ label: "Create", value: ProjectPermissionApprovalRequestActions.Create }
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
[ProjectPermissionSub.ApprovalRequestGrants]: {
|
||||||
|
title: "Approval Request Grants",
|
||||||
|
actions: [
|
||||||
|
{ label: "Read", value: ProjectPermissionApprovalRequestGrantActions.Read },
|
||||||
|
{ label: "Revoke", value: ProjectPermissionApprovalRequestGrantActions.Revoke }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -1993,7 +2021,8 @@ const SharedPermissionSubjects = {
|
|||||||
[ProjectPermissionSub.Project]: true,
|
[ProjectPermissionSub.Project]: true,
|
||||||
[ProjectPermissionSub.Role]: true,
|
[ProjectPermissionSub.Role]: true,
|
||||||
[ProjectPermissionSub.Settings]: true,
|
[ProjectPermissionSub.Settings]: true,
|
||||||
[ProjectPermissionSub.ApprovalRequests]: true
|
[ProjectPermissionSub.ApprovalRequests]: true,
|
||||||
|
[ProjectPermissionSub.ApprovalRequestGrants]: true
|
||||||
};
|
};
|
||||||
|
|
||||||
const SecretsManagerPermissionSubjects = (enabled = false) => ({
|
const SecretsManagerPermissionSubjects = (enabled = false) => ({
|
||||||
|
|||||||
Reference in New Issue
Block a user