mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-09 20:28:31 +00:00
Merge pull request #4701 from Infisical/feat/sub-org
feat: sub organization
This commit is contained in:
Vendored
+4
@@ -48,6 +48,7 @@ import { TSshCertificateAuthorityServiceFactory } from "@app/ee/services/ssh/ssh
|
|||||||
import { TSshCertificateTemplateServiceFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-service";
|
import { TSshCertificateTemplateServiceFactory } from "@app/ee/services/ssh-certificate-template/ssh-certificate-template-service";
|
||||||
import { TSshHostServiceFactory } from "@app/ee/services/ssh-host/ssh-host-service";
|
import { TSshHostServiceFactory } from "@app/ee/services/ssh-host/ssh-host-service";
|
||||||
import { TSshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-service";
|
import { TSshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-service";
|
||||||
|
import { TSubOrgServiceFactory } from "@app/ee/services/sub-org/sub-org-service";
|
||||||
import { TTrustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-types";
|
import { TTrustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-types";
|
||||||
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
|
import { TAuthMode } from "@app/server/plugins/auth/inject-identity";
|
||||||
import { TAdditionalPrivilegeServiceFactory } from "@app/services/additional-privilege/additional-privilege-service";
|
import { TAdditionalPrivilegeServiceFactory } from "@app/services/additional-privilege/additional-privilege-service";
|
||||||
@@ -182,6 +183,8 @@ declare module "fastify" {
|
|||||||
type: ActorType;
|
type: ActorType;
|
||||||
id: string;
|
id: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
parentOrgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
};
|
};
|
||||||
rateLimits: RateLimitConfiguration;
|
rateLimits: RateLimitConfiguration;
|
||||||
// passport data
|
// passport data
|
||||||
@@ -335,6 +338,7 @@ declare module "fastify" {
|
|||||||
additionalPrivilege: TAdditionalPrivilegeServiceFactory;
|
additionalPrivilege: TAdditionalPrivilegeServiceFactory;
|
||||||
role: TRoleServiceFactory;
|
role: TRoleServiceFactory;
|
||||||
convertor: TConvertorServiceFactory;
|
convertor: TConvertorServiceFactory;
|
||||||
|
subOrganization: TSubOrgServiceFactory;
|
||||||
};
|
};
|
||||||
// this is exclusive use for middlewares in which we need to inject data
|
// this is exclusive use for middlewares in which we need to inject data
|
||||||
// everywhere else access using service layer
|
// everywhere else access using service layer
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { dropConstraintIfExists } from "@app/db/migrations/utils/dropConstraintIfExists";
|
||||||
|
|
||||||
|
import { AccessScope, TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
|
||||||
|
if (!hasParentOrgId) {
|
||||||
|
await knex.schema.alterTable(TableName.Organization, async (t) => {
|
||||||
|
// the one just above the chain
|
||||||
|
t.uuid("parentOrgId");
|
||||||
|
t.foreign("parentOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
// this would root organization containing various informations like billing etc
|
||||||
|
t.uuid("rootOrgId");
|
||||||
|
t.foreign("rootOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
|
||||||
|
await dropConstraintIfExists(TableName.Organization, "organizations_slug_unique", knex);
|
||||||
|
t.unique(["rootOrgId", "parentOrgId", "slug"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
// had to switch to raw for null not distinct
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasIdentityOrgCol = await knex.schema.hasColumn(TableName.Identity, "orgId");
|
||||||
|
if (!hasIdentityOrgCol) {
|
||||||
|
await knex.schema.alterTable(TableName.Identity, (t) => {
|
||||||
|
t.uuid("orgId");
|
||||||
|
t.foreign("orgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
||||||
|
});
|
||||||
|
|
||||||
|
await knex.raw(
|
||||||
|
`
|
||||||
|
UPDATE ?? AS identity
|
||||||
|
SET "orgId" = membership."scopeOrgId"
|
||||||
|
FROM ?? AS membership
|
||||||
|
WHERE
|
||||||
|
membership."actorIdentityId" = identity."id"
|
||||||
|
AND membership."scope" = ?
|
||||||
|
`,
|
||||||
|
[TableName.Identity, TableName.Membership, AccessScope.Organization]
|
||||||
|
);
|
||||||
|
|
||||||
|
await knex.schema.alterTable(TableName.Identity, (t) => {
|
||||||
|
t.uuid("orgId").notNullable().alter();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function down(knex: Knex): Promise<void> {
|
||||||
|
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
|
||||||
|
const hasRootOrgId = await knex.schema.hasColumn(TableName.Organization, "rootOrgId");
|
||||||
|
if (hasParentOrgId || hasRootOrgId) {
|
||||||
|
await knex.schema.alterTable(TableName.Organization, (t) => {
|
||||||
|
if (hasParentOrgId) t.dropColumn("parentOrgId");
|
||||||
|
if (hasRootOrgId) t.dropColumn("rootOrgId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const hasIdentityOrgCol = await knex.schema.hasColumn(TableName.Identity, "orgId");
|
||||||
|
if (hasIdentityOrgCol) {
|
||||||
|
await knex.schema.alterTable(TableName.Identity, (t) => {
|
||||||
|
t.dropColumn("orgId");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,7 +13,8 @@ export const IdentitiesSchema = z.object({
|
|||||||
authMethod: z.string().nullable().optional(),
|
authMethod: z.string().nullable().optional(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
hasDeleteProtection: z.boolean().default(false)
|
hasDeleteProtection: z.boolean().default(false),
|
||||||
|
orgId: z.string().uuid()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TIdentities = z.infer<typeof IdentitiesSchema>;
|
export type TIdentities = z.infer<typeof IdentitiesSchema>;
|
||||||
|
|||||||
@@ -316,6 +316,12 @@ export enum ActionProjectType {
|
|||||||
Any = "any"
|
Any = "any"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum OrganizationActionScope {
|
||||||
|
ChildOrganization = "child-organization-only",
|
||||||
|
ParentOrganization = "parent-organization-only",
|
||||||
|
Any = "any"
|
||||||
|
}
|
||||||
|
|
||||||
export enum TemporaryPermissionMode {
|
export enum TemporaryPermissionMode {
|
||||||
Relative = "relative"
|
Relative = "relative"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,9 @@ export const OrganizationsSchema = z.object({
|
|||||||
maxSharedSecretLifetime: z.number().default(2592000).nullable().optional(),
|
maxSharedSecretLifetime: z.number().default(2592000).nullable().optional(),
|
||||||
maxSharedSecretViewLimit: z.number().nullable().optional(),
|
maxSharedSecretViewLimit: z.number().nullable().optional(),
|
||||||
googleSsoAuthEnforced: z.boolean().default(false),
|
googleSsoAuthEnforced: z.boolean().default(false),
|
||||||
googleSsoAuthLastUsed: z.date().nullable().optional()
|
googleSsoAuthLastUsed: z.date().nullable().optional(),
|
||||||
|
parentOrgId: z.string().uuid().nullable().optional(),
|
||||||
|
rootOrgId: z.string().uuid().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
export type TOrganizations = z.infer<typeof OrganizationsSchema>;
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ export async function seed(knex: Knex): Promise<void> {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
id: seedData1.machineIdentity.id,
|
id: seedData1.machineIdentity.id,
|
||||||
name: seedData1.machineIdentity.name,
|
name: seedData1.machineIdentity.name,
|
||||||
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH
|
authMethod: IdentityAuthMethod.UNIVERSAL_AUTH,
|
||||||
|
orgId: seedData1.organization.id
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
const identityUa = await knex(TableName.IdentityUniversalAuth)
|
const identityUa = await knex(TableName.IdentityUniversalAuth)
|
||||||
|
|||||||
@@ -48,12 +48,14 @@ import { registerSshCertRouter } from "./ssh-certificate-router";
|
|||||||
import { registerSshCertificateTemplateRouter } from "./ssh-certificate-template-router";
|
import { registerSshCertificateTemplateRouter } from "./ssh-certificate-template-router";
|
||||||
import { registerSshHostGroupRouter } from "./ssh-host-group-router";
|
import { registerSshHostGroupRouter } from "./ssh-host-group-router";
|
||||||
import { registerSshHostRouter } from "./ssh-host-router";
|
import { registerSshHostRouter } from "./ssh-host-router";
|
||||||
|
import { registerSubOrgRouter } from "./sub-org-router";
|
||||||
import { registerTrustedIpRouter } from "./trusted-ip-router";
|
import { registerTrustedIpRouter } from "./trusted-ip-router";
|
||||||
import { registerUserAdditionalPrivilegeRouter } from "./user-additional-privilege-router";
|
import { registerUserAdditionalPrivilegeRouter } from "./user-additional-privilege-router";
|
||||||
|
|
||||||
export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
export const registerV1EERoutes = async (server: FastifyZodProvider) => {
|
||||||
// org role starts with organization
|
// org role starts with organization
|
||||||
await server.register(registerOrgRoleRouter, { prefix: "/organization" });
|
await server.register(registerOrgRoleRouter, { prefix: "/organization" });
|
||||||
|
await server.register(registerSubOrgRouter, { prefix: "/sub-organizations" });
|
||||||
await server.register(registerLicenseRouter, { prefix: "/organizations" });
|
await server.register(registerLicenseRouter, { prefix: "/organizations" });
|
||||||
|
|
||||||
// depreciated in favour of infisical workspace
|
// depreciated in favour of infisical workspace
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export const registerLicenseRouter = async (server: FastifyZodProvider) => {
|
|||||||
const plan = await server.services.license.getOrgPlan({
|
const plan = await server.services.license.getOrgPlan({
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorOrgId: req.permission.orgId,
|
actorOrgId: req.permission.rootOrgId,
|
||||||
actorAuthMethod: req.permission.authMethod,
|
actorAuthMethod: req.permission.authMethod,
|
||||||
orgId: req.params.organizationId,
|
orgId: req.params.organizationId,
|
||||||
refreshCache: req.query.refreshCache
|
refreshCache: req.query.refreshCache
|
||||||
|
|||||||
@@ -3,12 +3,35 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { AccessScope, OrgMembershipRole, OrgRolesSchema } from "@app/db/schemas";
|
import { AccessScope, OrgMembershipRole, OrgRolesSchema } from "@app/db/schemas";
|
||||||
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { OrgPermissionSchema } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionSchema, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
import { slugSchema } from "@app/server/lib/schemas";
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
import { AuthMode } from "@app/services/auth/auth-type";
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
const INVALID_SUBORG_PERMISSIONS = [
|
||||||
|
OrgPermissionSubjects.Sso,
|
||||||
|
OrgPermissionSubjects.Ldap,
|
||||||
|
OrgPermissionSubjects.Scim,
|
||||||
|
OrgPermissionSubjects.GithubOrgSync,
|
||||||
|
OrgPermissionSubjects.GithubOrgSyncManual,
|
||||||
|
OrgPermissionSubjects.Billing,
|
||||||
|
OrgPermissionSubjects.SubOrganization
|
||||||
|
];
|
||||||
|
|
||||||
|
const validateSubOrganizationSubjects = (permissions: unknown) => {
|
||||||
|
const invalidPermissionSubjects = (permissions as { subject: OrgPermissionSubjects }[])
|
||||||
|
.filter((el) => INVALID_SUBORG_PERMISSIONS.includes(el.subject))
|
||||||
|
.map((el) => el.subject);
|
||||||
|
if (invalidPermissionSubjects.length) {
|
||||||
|
const deduplication = Array.from(new Set(invalidPermissionSubjects));
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Suborganization contains invalid permission subjects: ${deduplication.join(",")}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
||||||
server.route({
|
server.route({
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -37,6 +60,11 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
const isSubOrganization = req.permission.rootOrgId !== req.permission.orgId;
|
||||||
|
if (isSubOrganization) {
|
||||||
|
validateSubOrganizationSubjects(req.body.permissions);
|
||||||
|
}
|
||||||
|
|
||||||
const stringifiedPermissions = JSON.stringify(packRules(req.body.permissions));
|
const stringifiedPermissions = JSON.stringify(packRules(req.body.permissions));
|
||||||
const role = await server.services.role.createRole({
|
const role = await server.services.role.createRole({
|
||||||
permission: req.permission,
|
permission: req.permission,
|
||||||
@@ -133,6 +161,11 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => {
|
|||||||
},
|
},
|
||||||
onRequest: verifyAuth([AuthMode.JWT]),
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
|
const isSubOrganization = req.permission.rootOrgId !== req.permission.orgId;
|
||||||
|
if (isSubOrganization && req.body.permissions) {
|
||||||
|
validateSubOrganizationSubjects(req.body.permissions);
|
||||||
|
}
|
||||||
|
|
||||||
const stringifiedPermissions = req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined;
|
const stringifiedPermissions = req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined;
|
||||||
const role = await server.services.role.updateRole({
|
const role = await server.services.role.updateRole({
|
||||||
permission: req.permission,
|
permission: req.permission,
|
||||||
|
|||||||
@@ -0,0 +1,163 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { OrganizationsSchema } from "@app/db/schemas";
|
||||||
|
import { EventType } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
|
import { ApiDocsTags, SUB_ORGANIZATIONS } from "@app/lib/api-docs";
|
||||||
|
import { readLimit, writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
const sanitizedSubOrganizationSchema = OrganizationsSchema.pick({
|
||||||
|
id: true,
|
||||||
|
name: true,
|
||||||
|
slug: true,
|
||||||
|
createdAt: true,
|
||||||
|
updatedAt: true,
|
||||||
|
parentOrgId: true
|
||||||
|
});
|
||||||
|
|
||||||
|
export const registerSubOrgRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SubOrganizations],
|
||||||
|
description: "Create a sub organization",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
body: z.object({
|
||||||
|
name: slugSchema().describe(SUB_ORGANIZATIONS.CREATE.name)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
organization: sanitizedSubOrganizationSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { organization } = await server.services.subOrganization.createSubOrg({
|
||||||
|
name: req.body.name,
|
||||||
|
permissionActor: req.permission
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.CREATE_SUB_ORGANIZATION,
|
||||||
|
metadata: {
|
||||||
|
name: req.body.name,
|
||||||
|
organizationId: organization.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { organization };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/",
|
||||||
|
config: {
|
||||||
|
rateLimit: readLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SubOrganizations],
|
||||||
|
description: "List of sub organizations",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
querystring: z.object({
|
||||||
|
limit: z.coerce.number().min(1).max(1000).default(25).describe(SUB_ORGANIZATIONS.LIST.limit),
|
||||||
|
offset: z.coerce.number().min(0).default(0).describe(SUB_ORGANIZATIONS.LIST.offset),
|
||||||
|
isAccessible: z
|
||||||
|
.enum(["true", "false"])
|
||||||
|
.optional()
|
||||||
|
.transform((value) => value === "true")
|
||||||
|
.describe(SUB_ORGANIZATIONS.LIST.isAccessible)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
organizations: sanitizedSubOrganizationSchema.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { organizations } = await server.services.subOrganization.listSubOrgs({
|
||||||
|
permissionActor: req.permission,
|
||||||
|
data: {
|
||||||
|
limit: req.query.limit,
|
||||||
|
offset: req.query.offset,
|
||||||
|
isAccessible: req.query.isAccessible
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { organizations };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "PATCH",
|
||||||
|
url: "/:subOrgId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
hide: false,
|
||||||
|
tags: [ApiDocsTags.SubOrganizations],
|
||||||
|
description: "Update a sub organization",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: z.object({
|
||||||
|
subOrgId: z.string().trim().describe(SUB_ORGANIZATIONS.UPDATE.subOrgId)
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
name: slugSchema().describe(SUB_ORGANIZATIONS.UPDATE.name)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
organization: sanitizedSubOrganizationSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { organization } = await server.services.subOrganization.updateSubOrg({
|
||||||
|
subOrgId: req.params.subOrgId,
|
||||||
|
name: req.body.name,
|
||||||
|
permissionActor: req.permission
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.services.auditLog.createAuditLog({
|
||||||
|
...req.auditLogInfo,
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
event: {
|
||||||
|
type: EventType.UPDATE_SUB_ORGANIZATION,
|
||||||
|
metadata: {
|
||||||
|
name: req.body.name,
|
||||||
|
organizationId: organization.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { organization };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
|
|
||||||
import { TAuditLogs } from "@app/db/schemas";
|
import { OrganizationActionScope, TAuditLogs } from "@app/db/schemas";
|
||||||
import {
|
import {
|
||||||
decryptLogStream,
|
decryptLogStream,
|
||||||
decryptLogStreamCredentials,
|
decryptLogStreamCredentials,
|
||||||
@@ -45,13 +45,14 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
scope: OrganizationActionScope.Any,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
actorId: actor.id,
|
||||||
actor.authMethod,
|
orgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
actorOrgId: actor.orgId
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -94,13 +95,14 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
const logStream = await auditLogStreamDAL.findById(logStreamId);
|
const logStream = await auditLogStreamDAL.findById(logStreamId);
|
||||||
if (!logStream) throw new NotFoundError({ message: `Audit Log Stream with ID '${logStreamId}' not found` });
|
if (!logStream) throw new NotFoundError({ message: `Audit Log Stream with ID '${logStreamId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
scope: OrganizationActionScope.Any,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
actorId: actor.id,
|
||||||
actor.authMethod,
|
orgId: actor.orgId,
|
||||||
logStream.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
actorOrgId: actor.orgId
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -160,13 +162,14 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
const logStream = await auditLogStreamDAL.findById(logStreamId);
|
const logStream = await auditLogStreamDAL.findById(logStreamId);
|
||||||
if (!logStream) throw new NotFoundError({ message: `Audit Log Stream with ID '${logStreamId}' not found` });
|
if (!logStream) throw new NotFoundError({ message: `Audit Log Stream with ID '${logStreamId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
scope: OrganizationActionScope.Any,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
actorId: actor.id,
|
||||||
actor.authMethod,
|
orgId: actor.orgId,
|
||||||
logStream.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
actorOrgId: actor.orgId
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -185,14 +188,14 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
const logStream = await auditLogStreamDAL.findById(logStreamId);
|
const logStream = await auditLogStreamDAL.findById(logStreamId);
|
||||||
|
|
||||||
if (!logStream) throw new NotFoundError({ message: `Audit log stream with ID '${logStreamId}' not found` });
|
if (!logStream) throw new NotFoundError({ message: `Audit log stream with ID '${logStreamId}' not found` });
|
||||||
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
scope: OrganizationActionScope.Any,
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
logStream.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -206,13 +209,14 @@ export const auditLogStreamServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const list = async (actor: OrgServiceActor) => {
|
const list = async (actor: OrgServiceActor) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
scope: OrganizationActionScope.Any,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
actorId: actor.id,
|
||||||
actor.authMethod,
|
orgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
actorOrgId: actor.orgId
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { requestContext } from "@fastify/request-context";
|
import { requestContext } from "@fastify/request-context";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
import { ActorType } from "@app/services/auth/auth-type";
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
@@ -47,13 +47,14 @@ export const auditLogServiceFactory = ({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// Organization-wide logs
|
// Organization-wide logs
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionAuditLogsActions.Read,
|
OrgPermissionAuditLogsActions.Read,
|
||||||
|
|||||||
@@ -173,6 +173,9 @@ export enum EventType {
|
|||||||
UPDATE_TOKEN_IDENTITY_TOKEN_AUTH = "update-token-identity-token-auth",
|
UPDATE_TOKEN_IDENTITY_TOKEN_AUTH = "update-token-identity-token-auth",
|
||||||
GET_TOKENS_IDENTITY_TOKEN_AUTH = "get-tokens-identity-token-auth",
|
GET_TOKENS_IDENTITY_TOKEN_AUTH = "get-tokens-identity-token-auth",
|
||||||
|
|
||||||
|
CREATE_SUB_ORGANIZATION = "create-sub-organization",
|
||||||
|
UPDATE_SUB_ORGANIZATION = "update-sub-organization",
|
||||||
|
|
||||||
ADD_IDENTITY_TOKEN_AUTH = "add-identity-token-auth",
|
ADD_IDENTITY_TOKEN_AUTH = "add-identity-token-auth",
|
||||||
UPDATE_IDENTITY_TOKEN_AUTH = "update-identity-token-auth",
|
UPDATE_IDENTITY_TOKEN_AUTH = "update-identity-token-auth",
|
||||||
GET_IDENTITY_TOKEN_AUTH = "get-identity-token-auth",
|
GET_IDENTITY_TOKEN_AUTH = "get-identity-token-auth",
|
||||||
@@ -616,6 +619,22 @@ interface GetSecretsEvent {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface CreateSubOrganizationEvent {
|
||||||
|
type: EventType.CREATE_SUB_ORGANIZATION;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
organizationId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface UpdateSubOrganizationEvent {
|
||||||
|
type: EventType.UPDATE_SUB_ORGANIZATION;
|
||||||
|
metadata: {
|
||||||
|
name: string;
|
||||||
|
organizationId: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
type TSecretMetadata = { key: string; value: string }[];
|
type TSecretMetadata = { key: string; value: string }[];
|
||||||
|
|
||||||
interface GetSecretEvent {
|
interface GetSecretEvent {
|
||||||
@@ -3964,6 +3983,8 @@ interface PamResourceDeleteEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type Event =
|
export type Event =
|
||||||
|
| CreateSubOrganizationEvent
|
||||||
|
| UpdateSubOrganizationEvent
|
||||||
| GetSecretsEvent
|
| GetSecretsEvent
|
||||||
| GetSecretEvent
|
| GetSecretEvent
|
||||||
| CreateSecretEvent
|
| CreateSecretEvent
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError, subject } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import {
|
import {
|
||||||
@@ -134,13 +134,14 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
isGatewayV1 = false;
|
isGatewayV1 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission: orgPermission } = await permissionService.getOrgPermission(
|
const { permission: orgPermission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
gateway?.orgId ?? gatewayv2?.orgId,
|
orgId: gateway?.orgId || gatewayv2?.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(orgPermission).throwUnlessCan(
|
ForbiddenError.from(orgPermission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.AttachGateways,
|
OrgPermissionGatewayActions.AttachGateways,
|
||||||
@@ -297,13 +298,14 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
isGatewayV1 = false;
|
isGatewayV1 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission: orgPermission } = await permissionService.getOrgPermission(
|
const { permission: orgPermission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: gateway?.orgId || gatewayv2?.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(orgPermission).throwUnlessCan(
|
ForbiddenError.from(orgPermission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.AttachGateways,
|
OrgPermissionGatewayActions.AttachGateways,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { STSServiceException } from "@aws-sdk/client-sts";
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
|
|
||||||
|
import { OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/errors";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
||||||
@@ -51,13 +52,14 @@ export const externalKmsServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TCreateExternalKmsDTO) => {
|
}: TCreateExternalKmsDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Kms);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Kms);
|
||||||
const plan = await licenseService.getPlan(actorOrgId);
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
@@ -154,13 +156,14 @@ export const externalKmsServiceFactory = ({
|
|||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TUpdateExternalKmsDTO) => {
|
}: TUpdateExternalKmsDTO) => {
|
||||||
const kmsDoc = await kmsDAL.findById(kmsId);
|
const kmsDoc = await kmsDAL.findById(kmsId);
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
kmsDoc.orgId,
|
orgId: kmsDoc.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Kms);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Kms);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(kmsDoc.orgId);
|
const plan = await licenseService.getPlan(kmsDoc.orgId);
|
||||||
@@ -257,13 +260,14 @@ export const externalKmsServiceFactory = ({
|
|||||||
|
|
||||||
const deleteById = async ({ actor, id: kmsId, actorId, actorOrgId, actorAuthMethod }: TDeleteExternalKmsDTO) => {
|
const deleteById = async ({ actor, id: kmsId, actorId, actorOrgId, actorAuthMethod }: TDeleteExternalKmsDTO) => {
|
||||||
const kmsDoc = await kmsDAL.findById(kmsId);
|
const kmsDoc = await kmsDAL.findById(kmsId);
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
kmsDoc.orgId,
|
orgId: kmsDoc.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Kms);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Kms);
|
||||||
|
|
||||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||||
@@ -278,13 +282,14 @@ export const externalKmsServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const list = async ({ actor, actorId, actorOrgId, actorAuthMethod }: TListExternalKmsDTO) => {
|
const list = async ({ actor, actorId, actorOrgId, actorAuthMethod }: TListExternalKmsDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Kms);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Kms);
|
||||||
|
|
||||||
const externalKmsDocs = await externalKmsDAL.find({ orgId: actorOrgId });
|
const externalKmsDocs = await externalKmsDAL.find({ orgId: actorOrgId });
|
||||||
@@ -294,13 +299,14 @@ export const externalKmsServiceFactory = ({
|
|||||||
|
|
||||||
const findById = async ({ actor, actorId, actorOrgId, actorAuthMethod, id: kmsId }: TGetExternalKmsByIdDTO) => {
|
const findById = async ({ actor, actorId, actorOrgId, actorAuthMethod, id: kmsId }: TGetExternalKmsByIdDTO) => {
|
||||||
const kmsDoc = await kmsDAL.findById(kmsId);
|
const kmsDoc = await kmsDAL.findById(kmsId);
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
kmsDoc.orgId,
|
orgId: kmsDoc.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Kms);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Kms);
|
||||||
|
|
||||||
@@ -342,13 +348,14 @@ export const externalKmsServiceFactory = ({
|
|||||||
name: kmsName
|
name: kmsName
|
||||||
}: TGetExternalKmsBySlugDTO) => {
|
}: TGetExternalKmsBySlugDTO) => {
|
||||||
const kmsDoc = await kmsDAL.findOne({ name: kmsName, orgId: actorOrgId });
|
const kmsDoc = await kmsDAL.findOne({ name: kmsName, orgId: actorOrgId });
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
kmsDoc.orgId,
|
orgId: kmsDoc.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Kms);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Kms);
|
||||||
|
|
||||||
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
const externalKmsDoc = await externalKmsDAL.findOne({ kmsKeyId: kmsDoc.id });
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import net from "node:net";
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import * as x509 from "@peculiar/x509";
|
import * as x509 from "@peculiar/x509";
|
||||||
|
|
||||||
import { OrgMembershipRole, TRelays } from "@app/db/schemas";
|
import { OrganizationActionScope, OrgMembershipRole, TRelays } from "@app/db/schemas";
|
||||||
import { PgSqlLock } from "@app/keystore/keystore";
|
import { PgSqlLock } from "@app/keystore/keystore";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { DatabaseErrorCode } from "@app/lib/error-codes";
|
import { DatabaseErrorCode } from "@app/lib/error-codes";
|
||||||
@@ -73,13 +73,14 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor: ActorType.IDENTITY,
|
||||||
actorId,
|
actorId,
|
||||||
orgId,
|
orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
orgId
|
actorOrgId: orgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.CreateGateways,
|
OrgPermissionGatewayActions.CreateGateways,
|
||||||
@@ -258,13 +259,14 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const listGateways = async ({ orgPermission }: { orgPermission: OrgServiceActor }) => {
|
const listGateways = async ({ orgPermission }: { orgPermission: OrgServiceActor }) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actor: orgPermission.type,
|
||||||
orgPermission.id,
|
actorId: orgPermission.id,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.ListGateways,
|
OrgPermissionGatewayActions.ListGateways,
|
||||||
@@ -815,13 +817,14 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: `Gateway ${id} not found` });
|
throw new NotFoundError({ message: `Gateway ${id} not found` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actor: orgPermission.type,
|
||||||
orgPermission.id,
|
actorId: orgPermission.id,
|
||||||
gateway.orgId,
|
orgId: gateway.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.DeleteGateways,
|
OrgPermissionGatewayActions.DeleteGateways,
|
||||||
@@ -845,13 +848,14 @@ export const gatewayV2ServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getPamSessionKey = async ({ orgPermission }: { orgPermission: OrgServiceActor }) => {
|
const getPamSessionKey = async ({ orgPermission }: { orgPermission: OrgServiceActor }) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actor: orgPermission.type,
|
||||||
orgPermission.id,
|
actorId: orgPermission.id,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.CreateGateways,
|
OrgPermissionGatewayActions.CreateGateways,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import * as x509 from "@peculiar/x509";
|
import * as x509 from "@peculiar/x509";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { KeyStorePrefixes, PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
|
import { KeyStorePrefixes, PgSqlLock, TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
@@ -68,13 +69,14 @@ export const gatewayServiceFactory = ({
|
|||||||
"Gateway handshake failed due to organization plan restrictions. Please upgrade your instance to Infisical's Enterprise plan."
|
"Gateway handshake failed due to organization plan restrictions. Please upgrade your instance to Infisical's Enterprise plan."
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
actorId,
|
actorId,
|
||||||
orgId,
|
orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
orgId
|
actorOrgId: orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.CreateGateways,
|
OrgPermissionGatewayActions.CreateGateways,
|
||||||
OrgPermissionSubjects.Gateway
|
OrgPermissionSubjects.Gateway
|
||||||
@@ -480,13 +482,14 @@ export const gatewayServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const listGateways = async ({ orgPermission }: TListGatewaysDTO) => {
|
const listGateways = async ({ orgPermission }: TListGatewaysDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actor: orgPermission.type,
|
||||||
orgPermission.id,
|
actorId: orgPermission.id,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.ListGateways,
|
OrgPermissionGatewayActions.ListGateways,
|
||||||
OrgPermissionSubjects.Gateway
|
OrgPermissionSubjects.Gateway
|
||||||
@@ -501,13 +504,14 @@ export const gatewayServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getGatewayById = async ({ orgPermission, id }: TGetGatewayByIdDTO) => {
|
const getGatewayById = async ({ orgPermission, id }: TGetGatewayByIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actor: orgPermission.type,
|
||||||
orgPermission.id,
|
actorId: orgPermission.id,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.ListGateways,
|
OrgPermissionGatewayActions.ListGateways,
|
||||||
OrgPermissionSubjects.Gateway
|
OrgPermissionSubjects.Gateway
|
||||||
@@ -521,13 +525,14 @@ export const gatewayServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateGatewayById = async ({ orgPermission, id, name }: TUpdateGatewayByIdDTO) => {
|
const updateGatewayById = async ({ orgPermission, id, name }: TUpdateGatewayByIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actor: orgPermission.type,
|
||||||
orgPermission.id,
|
actorId: orgPermission.id,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.EditGateways,
|
OrgPermissionGatewayActions.EditGateways,
|
||||||
OrgPermissionSubjects.Gateway
|
OrgPermissionSubjects.Gateway
|
||||||
@@ -542,13 +547,14 @@ export const gatewayServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deleteGatewayById = async ({ orgPermission, id }: TGetGatewayByIdDTO) => {
|
const deleteGatewayById = async ({ orgPermission, id }: TGetGatewayByIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actor: orgPermission.type,
|
||||||
orgPermission.id,
|
actorId: orgPermission.id,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.DeleteGateways,
|
OrgPermissionGatewayActions.DeleteGateways,
|
||||||
OrgPermissionSubjects.Gateway
|
OrgPermissionSubjects.Gateway
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { paginateGraphql } from "@octokit/plugin-paginate-graphql";
|
|||||||
import { Octokit as OctokitRest } from "@octokit/rest";
|
import { Octokit as OctokitRest } from "@octokit/rest";
|
||||||
import RE2 from "re2";
|
import RE2 from "re2";
|
||||||
|
|
||||||
import { AccessScope, OrgMembershipRole } from "@app/db/schemas";
|
import { AccessScope, OrganizationActionScope, OrgMembershipRole } from "@app/db/schemas";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { groupBy } from "@app/lib/fn";
|
import { groupBy } from "@app/lib/fn";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
@@ -104,13 +104,14 @@ export const githubOrgSyncServiceFactory = ({
|
|||||||
githubOrgAccessToken,
|
githubOrgAccessToken,
|
||||||
isActive
|
isActive
|
||||||
}: TCreateGithubOrgSyncDTO) => {
|
}: TCreateGithubOrgSyncDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
orgPermission.id,
|
actor: orgPermission.type,
|
||||||
orgPermission.orgId,
|
actorId: orgPermission.id,
|
||||||
orgPermission.authMethod,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.orgId
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
);
|
actorOrgId: orgPermission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.GithubOrgSync);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.GithubOrgSync);
|
||||||
const plan = await licenseService.getPlan(orgPermission.orgId);
|
const plan = await licenseService.getPlan(orgPermission.orgId);
|
||||||
@@ -162,13 +163,14 @@ export const githubOrgSyncServiceFactory = ({
|
|||||||
githubOrgAccessToken,
|
githubOrgAccessToken,
|
||||||
isActive
|
isActive
|
||||||
}: TUpdateGithubOrgSyncDTO) => {
|
}: TUpdateGithubOrgSyncDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actor: orgPermission.type,
|
||||||
orgPermission.id,
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
orgPermission.orgId,
|
actorId: orgPermission.id,
|
||||||
orgPermission.authMethod,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.orgId
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
);
|
actorOrgId: orgPermission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.GithubOrgSync);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.GithubOrgSync);
|
||||||
const plan = await licenseService.getPlan(orgPermission.orgId);
|
const plan = await licenseService.getPlan(orgPermission.orgId);
|
||||||
@@ -226,13 +228,14 @@ export const githubOrgSyncServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deleteGithubOrgSync = async ({ orgPermission }: TDeleteGithubOrgSyncDTO) => {
|
const deleteGithubOrgSync = async ({ orgPermission }: TDeleteGithubOrgSyncDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actor: orgPermission.type,
|
||||||
orgPermission.id,
|
actorId: orgPermission.id,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.GithubOrgSync);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.GithubOrgSync);
|
||||||
|
|
||||||
@@ -256,13 +259,14 @@ export const githubOrgSyncServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getGithubOrgSync = async ({ orgPermission }: TDeleteGithubOrgSyncDTO) => {
|
const getGithubOrgSync = async ({ orgPermission }: TDeleteGithubOrgSyncDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actorId: orgPermission.id,
|
||||||
orgPermission.id,
|
actor: orgPermission.type,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.GithubOrgSync);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.GithubOrgSync);
|
||||||
|
|
||||||
@@ -422,13 +426,14 @@ export const githubOrgSyncServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const validateGithubToken = async ({ orgPermission, githubOrgAccessToken }: TValidateGithubTokenDTO) => {
|
const validateGithubToken = async ({ orgPermission, githubOrgAccessToken }: TValidateGithubTokenDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
actorId: orgPermission.id,
|
||||||
orgPermission.id,
|
actor: orgPermission.type,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
orgPermission.orgId
|
actorOrgId: orgPermission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.GithubOrgSync);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.GithubOrgSync);
|
||||||
|
|
||||||
@@ -509,13 +514,14 @@ export const githubOrgSyncServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const syncAllTeams = async ({ orgPermission }: TSyncAllTeamsDTO): Promise<TSyncResult> => {
|
const syncAllTeams = async ({ orgPermission }: TSyncAllTeamsDTO): Promise<TSyncResult> => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
orgPermission.type,
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
orgPermission.id,
|
actor: orgPermission.type,
|
||||||
orgPermission.orgId,
|
orgId: orgPermission.orgId,
|
||||||
orgPermission.authMethod,
|
actorId: orgPermission.id,
|
||||||
orgPermission.orgId
|
actorAuthMethod: orgPermission.authMethod,
|
||||||
);
|
actorOrgId: orgPermission.orgId
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Edit,
|
OrgPermissionActions.Edit,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
|
|
||||||
import { AccessScope, OrgMembershipRole, TRoles } from "@app/db/schemas";
|
import { AccessScope, OrganizationActionScope, OrgMembershipRole, TRoles } from "@app/db/schemas";
|
||||||
import { TOidcConfigDALFactory } from "@app/ee/services/oidc/oidc-config-dal";
|
import { TOidcConfigDALFactory } from "@app/ee/services/oidc/oidc-config-dal";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
||||||
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
import { alphaNumericNanoId } from "@app/lib/nanoid";
|
||||||
@@ -73,13 +73,14 @@ export const groupServiceFactory = ({
|
|||||||
const createGroup = async ({ name, slug, role, actor, actorId, actorAuthMethod, actorOrgId }: TCreateGroupDTO) => {
|
const createGroup = async ({ name, slug, role, actor, actorId, actorAuthMethod, actorOrgId }: TCreateGroupDTO) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Create, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Create, OrgPermissionSubjects.Groups);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(actorOrgId);
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
@@ -167,13 +168,14 @@ export const groupServiceFactory = ({
|
|||||||
}: TUpdateGroupDTO) => {
|
}: TUpdateGroupDTO) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Edit, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Edit, OrgPermissionSubjects.Groups);
|
||||||
|
|
||||||
@@ -270,13 +272,14 @@ export const groupServiceFactory = ({
|
|||||||
const deleteGroup = async ({ id, actor, actorId, actorAuthMethod, actorOrgId }: TDeleteGroupDTO) => {
|
const deleteGroup = async ({ id, actor, actorId, actorAuthMethod, actorOrgId }: TDeleteGroupDTO) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Delete, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Delete, OrgPermissionSubjects.Groups);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(actorOrgId);
|
const plan = await licenseService.getPlan(actorOrgId);
|
||||||
@@ -297,17 +300,18 @@ export const groupServiceFactory = ({
|
|||||||
const getGroupById = async ({ id, actor, actorId, actorAuthMethod, actorOrgId }: TGetGroupByIdDTO) => {
|
const getGroupById = async ({ id, actor, actorId, actorAuthMethod, actorOrgId }: TGetGroupByIdDTO) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Read, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Read, OrgPermissionSubjects.Groups);
|
||||||
|
|
||||||
const group = await groupDAL.findById(id);
|
const group = await groupDAL.findById(id);
|
||||||
if (!group) {
|
if (!group || group.orgId !== actorOrgId) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Cannot find group with ID ${id}`
|
message: `Cannot find group with ID ${id}`
|
||||||
});
|
});
|
||||||
@@ -330,13 +334,14 @@ export const groupServiceFactory = ({
|
|||||||
}: TListGroupUsersDTO) => {
|
}: TListGroupUsersDTO) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Read, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Read, OrgPermissionSubjects.Groups);
|
||||||
|
|
||||||
const group = await groupDAL.findOne({
|
const group = await groupDAL.findOne({
|
||||||
@@ -365,13 +370,14 @@ export const groupServiceFactory = ({
|
|||||||
const addUserToGroup = async ({ id, username, actor, actorId, actorAuthMethod, actorOrgId }: TAddUserToGroupDTO) => {
|
const addUserToGroup = async ({ id, username, actor, actorId, actorAuthMethod, actorOrgId }: TAddUserToGroupDTO) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Edit, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Edit, OrgPermissionSubjects.Groups);
|
||||||
|
|
||||||
// check if group with slug exists
|
// check if group with slug exists
|
||||||
@@ -451,13 +457,14 @@ export const groupServiceFactory = ({
|
|||||||
}: TRemoveUserFromGroupDTO) => {
|
}: TRemoveUserFromGroupDTO) => {
|
||||||
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
if (!actorOrgId) throw new UnauthorizedError({ message: "No organization ID provided in request" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Edit, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Edit, OrgPermissionSubjects.Groups);
|
||||||
|
|
||||||
// check if group with slug exists
|
// check if group with slug exists
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
|
import { OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import {
|
import {
|
||||||
@@ -68,13 +69,14 @@ export const identityAuthTemplateServiceFactory = ({
|
|||||||
templateFields: Record<string, unknown>;
|
templateFields: Record<string, unknown>;
|
||||||
} & Omit<TOrgPermission, "orgId">) => {
|
} & Omit<TOrgPermission, "orgId">) => {
|
||||||
await $checkPlan(actorOrgId);
|
await $checkPlan(actorOrgId);
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions.CreateTemplates,
|
OrgPermissionMachineIdentityAuthTemplateActions.CreateTemplates,
|
||||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||||
@@ -113,13 +115,14 @@ export const identityAuthTemplateServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: "Template not found" });
|
throw new NotFoundError({ message: "Template not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
template.orgId,
|
orgId: template.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions.EditTemplates,
|
OrgPermissionMachineIdentityAuthTemplateActions.EditTemplates,
|
||||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||||
@@ -227,13 +230,14 @@ export const identityAuthTemplateServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: "Template not found" });
|
throw new NotFoundError({ message: "Template not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
template.orgId,
|
orgId: template.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions.DeleteTemplates,
|
OrgPermissionMachineIdentityAuthTemplateActions.DeleteTemplates,
|
||||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||||
@@ -282,13 +286,14 @@ export const identityAuthTemplateServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: "Template not found" });
|
throw new NotFoundError({ message: "Template not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
template.orgId,
|
orgId: template.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates,
|
OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates,
|
||||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||||
@@ -316,13 +321,14 @@ export const identityAuthTemplateServiceFactory = ({
|
|||||||
actorOrgId
|
actorOrgId
|
||||||
}: TListIdentityAuthTemplatesDTO) => {
|
}: TListIdentityAuthTemplatesDTO) => {
|
||||||
await $checkPlan(actorOrgId);
|
await $checkPlan(actorOrgId);
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates,
|
OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates,
|
||||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||||
@@ -352,13 +358,14 @@ export const identityAuthTemplateServiceFactory = ({
|
|||||||
actorOrgId
|
actorOrgId
|
||||||
}: TGetTemplatesByAuthMethodDTO) => {
|
}: TGetTemplatesByAuthMethodDTO) => {
|
||||||
await $checkPlan(actorOrgId);
|
await $checkPlan(actorOrgId);
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions.AttachTemplates,
|
OrgPermissionMachineIdentityAuthTemplateActions.AttachTemplates,
|
||||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||||
@@ -385,13 +392,14 @@ export const identityAuthTemplateServiceFactory = ({
|
|||||||
actorOrgId
|
actorOrgId
|
||||||
}: TFindTemplateUsagesDTO) => {
|
}: TFindTemplateUsagesDTO) => {
|
||||||
await $checkPlan(actorOrgId);
|
await $checkPlan(actorOrgId);
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates,
|
OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates,
|
||||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||||
@@ -415,13 +423,14 @@ export const identityAuthTemplateServiceFactory = ({
|
|||||||
actorOrgId
|
actorOrgId
|
||||||
}: TUnlinkTemplateUsageDTO) => {
|
}: TUnlinkTemplateUsageDTO) => {
|
||||||
await $checkPlan(actorOrgId);
|
await $checkPlan(actorOrgId);
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionMachineIdentityAuthTemplateActions.UnlinkTemplates,
|
OrgPermissionMachineIdentityAuthTemplateActions.UnlinkTemplates,
|
||||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
|
import { OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
import { TKmsKeyDALFactory } from "@app/services/kms/kms-key-dal";
|
||||||
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
import { TKmsServiceFactory } from "@app/services/kms/kms-service";
|
||||||
@@ -46,13 +47,14 @@ export const kmipOperationServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TKmipCreateDTO) => {
|
}: TKmipCreateDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
@@ -78,13 +80,14 @@ export const kmipOperationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const destroy = async ({ projectId, id, clientId, actor, actorId, actorOrgId, actorAuthMethod }: TKmipDestroyDTO) => {
|
const destroy = async ({ projectId, id, clientId, actor, actorId, actorOrgId, actorAuthMethod }: TKmipDestroyDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
@@ -131,13 +134,14 @@ export const kmipOperationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const get = async ({ projectId, id, clientId, actor, actorId, actorAuthMethod, actorOrgId }: TKmipGetDTO) => {
|
const get = async ({ projectId, id, clientId, actor, actorId, actorAuthMethod, actorOrgId }: TKmipGetDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
@@ -189,13 +193,14 @@ export const kmipOperationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const activate = async ({ projectId, id, clientId, actor, actorId, actorAuthMethod, actorOrgId }: TKmipGetDTO) => {
|
const activate = async ({ projectId, id, clientId, actor, actorId, actorAuthMethod, actorOrgId }: TKmipGetDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
@@ -226,13 +231,14 @@ export const kmipOperationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const revoke = async ({ projectId, id, clientId, actor, actorId, actorAuthMethod, actorOrgId }: TKmipRevokeDTO) => {
|
const revoke = async ({ projectId, id, clientId, actor, actorId, actorAuthMethod, actorOrgId }: TKmipRevokeDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
@@ -287,13 +293,14 @@ export const kmipOperationServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TKmipGetAttributesDTO) => {
|
}: TKmipGetAttributesDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
@@ -339,13 +346,14 @@ export const kmipOperationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const locate = async ({ projectId, clientId, actor, actorId, actorAuthMethod, actorOrgId }: TKmipLocateDTO) => {
|
const locate = async ({ projectId, clientId, actor, actorId, actorAuthMethod, actorOrgId }: TKmipLocateDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
@@ -377,13 +385,14 @@ export const kmipOperationServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
kmipMetadata
|
kmipMetadata
|
||||||
}: TKmipRegisterDTO) => {
|
}: TKmipRegisterDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import * as x509 from "@peculiar/x509";
|
import * as x509 from "@peculiar/x509";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, InternalServerError, NotFoundError } from "@app/lib/errors";
|
||||||
import { isValidIp } from "@app/lib/ip";
|
import { isValidIp } from "@app/lib/ip";
|
||||||
@@ -401,13 +401,14 @@ export const kmipServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const setupOrgKmip = async ({ caKeyAlgorithm, actorOrgId, actor, actorId, actorAuthMethod }: TSetupOrgKmipDTO) => {
|
const setupOrgKmip = async ({ caKeyAlgorithm, actorOrgId, actor, actorId, actorAuthMethod }: TSetupOrgKmipDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Setup, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Setup, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
const kmipConfig = await kmipOrgConfigDAL.findOne({
|
const kmipConfig = await kmipOrgConfigDAL.findOne({
|
||||||
@@ -566,7 +567,14 @@ export const kmipServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getOrgKmip = async ({ actorOrgId, actor, actorId, actorAuthMethod }: TGetOrgKmipDTO) => {
|
const getOrgKmip = async ({ actorOrgId, actor, actorId, actorAuthMethod }: TGetOrgKmipDTO) => {
|
||||||
await permissionService.getOrgPermission(actor, actorId, actorOrgId, actorAuthMethod, actorOrgId);
|
await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
|
|
||||||
const kmipConfig = await kmipOrgConfigDAL.findOne({
|
const kmipConfig = await kmipOrgConfigDAL.findOne({
|
||||||
orgId: actorOrgId
|
orgId: actorOrgId
|
||||||
@@ -759,13 +767,14 @@ export const kmipServiceFactory = ({
|
|||||||
keyAlgorithm,
|
keyAlgorithm,
|
||||||
hostnamesOrIps
|
hostnamesOrIps
|
||||||
}: TRegisterServerDTO) => {
|
}: TRegisterServerDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionKmipActions.Proxy, OrgPermissionSubjects.Kmip);
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,14 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { AccessScope, OrgMembershipStatus, TableName, TLdapConfigsUpdate, TUsers } from "@app/db/schemas";
|
import {
|
||||||
|
AccessScope,
|
||||||
|
OrganizationActionScope,
|
||||||
|
OrgMembershipStatus,
|
||||||
|
TableName,
|
||||||
|
TLdapConfigsUpdate,
|
||||||
|
TUsers
|
||||||
|
} from "@app/db/schemas";
|
||||||
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
||||||
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns";
|
import { addUsersToGroupByUserIds, removeUsersFromGroupByUserIds } from "@app/ee/services/group/group-fns";
|
||||||
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
||||||
@@ -119,7 +126,14 @@ export const ldapConfigServiceFactory = ({
|
|||||||
groupSearchFilter,
|
groupSearchFilter,
|
||||||
caCert
|
caCert
|
||||||
}: TCreateLdapCfgDTO) => {
|
}: TCreateLdapCfgDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Ldap);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Ldap);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
@@ -238,7 +252,14 @@ export const ldapConfigServiceFactory = ({
|
|||||||
groupSearchFilter,
|
groupSearchFilter,
|
||||||
caCert
|
caCert
|
||||||
}: TUpdateLdapCfgDTO) => {
|
}: TUpdateLdapCfgDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Ldap);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Ldap);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
@@ -316,7 +337,14 @@ export const ldapConfigServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TGetLdapCfgDTO) => {
|
}: TGetLdapCfgDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Ldap);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Ldap);
|
||||||
return getLdapCfg({
|
return getLdapCfg({
|
||||||
orgId
|
orgId
|
||||||
@@ -649,7 +677,14 @@ export const ldapConfigServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TGetLdapGroupMapsDTO) => {
|
}: TGetLdapGroupMapsDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Ldap);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Ldap);
|
||||||
|
|
||||||
const ldapConfig = await ldapConfigDAL.findOne({
|
const ldapConfig = await ldapConfigDAL.findOne({
|
||||||
@@ -678,7 +713,14 @@ export const ldapConfigServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TCreateLdapGroupMapDTO) => {
|
}: TCreateLdapGroupMapDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Ldap);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Ldap);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
@@ -732,7 +774,14 @@ export const ldapConfigServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TDeleteLdapGroupMapDTO) => {
|
}: TDeleteLdapGroupMapDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Ldap);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Ldap);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
@@ -771,7 +820,14 @@ export const ldapConfigServiceFactory = ({
|
|||||||
caCert,
|
caCert,
|
||||||
url
|
url
|
||||||
}: TTestLdapConnectionDTO) => {
|
}: TTestLdapConnectionDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Ldap);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Ldap);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ export const licenseDALFactory = (db: TDbClient) => {
|
|||||||
const countOfOrgMembers = async (orgId: string | null, tx?: Knex) => {
|
const countOfOrgMembers = async (orgId: string | null, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const doc = await (tx || db.replicaNode())(TableName.Membership)
|
const doc = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
|
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
||||||
.where({ status: OrgMembershipStatus.Accepted, scope: AccessScope.Organization })
|
.where({ status: OrgMembershipStatus.Accepted, scope: AccessScope.Organization })
|
||||||
.andWhere((bd) => {
|
.andWhere((bd) => {
|
||||||
if (orgId) {
|
if (orgId) {
|
||||||
@@ -18,6 +19,7 @@ export const licenseDALFactory = (db: TDbClient) => {
|
|||||||
})
|
})
|
||||||
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.where(`${TableName.Users}.isGhost`, false)
|
.where(`${TableName.Users}.isGhost`, false)
|
||||||
|
.whereNull(`${TableName.Organization}.rootOrgId`)
|
||||||
.count();
|
.count();
|
||||||
return Number(doc?.[0]?.count ?? 0);
|
return Number(doc?.[0]?.count ?? 0);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -25,10 +27,31 @@ export const licenseDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const countOfOrgIdentities = async (orgId: string | null, tx?: Knex) => {
|
||||||
|
try {
|
||||||
|
// count org identities
|
||||||
|
const identityDoc = await (tx || db.replicaNode())(TableName.Identity)
|
||||||
|
.join(TableName.Organization, `${TableName.Identity}.orgId`, `${TableName.Organization}.id`)
|
||||||
|
.where((bd) => {
|
||||||
|
if (orgId) {
|
||||||
|
void bd.where(`${TableName.Organization}.rootOrgId`, orgId).orWhere(`${TableName.Organization}.id`, orgId);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
|
||||||
|
const identityCount = Number(identityDoc?.[0].count);
|
||||||
|
|
||||||
|
return identityCount;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "Count of Org Users + Identities" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const countOrgUsersAndIdentities = async (orgId: string | null, tx?: Knex) => {
|
const countOrgUsersAndIdentities = async (orgId: string | null, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
// count org users
|
// count org users
|
||||||
const userDoc = await (tx || db.replicaNode())(TableName.Membership)
|
const userDoc = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
|
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
||||||
.where({ status: OrgMembershipStatus.Accepted, scope: AccessScope.Organization })
|
.where({ status: OrgMembershipStatus.Accepted, scope: AccessScope.Organization })
|
||||||
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
.andWhere((bd) => {
|
.andWhere((bd) => {
|
||||||
@@ -38,17 +61,17 @@ export const licenseDALFactory = (db: TDbClient) => {
|
|||||||
})
|
})
|
||||||
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
|
||||||
.where(`${TableName.Users}.isGhost`, false)
|
.where(`${TableName.Users}.isGhost`, false)
|
||||||
|
.whereNull(`${TableName.Organization}.rootOrgId`)
|
||||||
.count();
|
.count();
|
||||||
|
|
||||||
const userCount = Number(userDoc?.[0].count);
|
const userCount = Number(userDoc?.[0].count);
|
||||||
|
|
||||||
// count org identities
|
// count org identities
|
||||||
const identityDoc = await (tx || db.replicaNode())(TableName.Membership)
|
const identityDoc = await (tx || db.replicaNode())(TableName.Identity)
|
||||||
.where({ scope: AccessScope.Organization })
|
.join(TableName.Organization, `${TableName.Identity}.orgId`, `${TableName.Organization}.id`)
|
||||||
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
|
||||||
.where((bd) => {
|
.where((bd) => {
|
||||||
if (orgId) {
|
if (orgId) {
|
||||||
void bd.where(`${TableName.Membership}.scopeOrgId`, orgId);
|
void bd.where(`${TableName.Organization}.rootOrgId`, orgId).orWhere(`${TableName.Organization}.id`, orgId);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.count();
|
.count();
|
||||||
@@ -61,5 +84,5 @@ export const licenseDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { countOfOrgMembers, countOrgUsersAndIdentities };
|
return { countOfOrgMembers, countOrgUsersAndIdentities, countOfOrgIdentities };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
|
|||||||
rbac: false,
|
rbac: false,
|
||||||
githubOrgSync: false,
|
githubOrgSync: false,
|
||||||
customRateLimits: false,
|
customRateLimits: false,
|
||||||
|
subOrganization: false,
|
||||||
customAlerts: false,
|
customAlerts: false,
|
||||||
secretAccessInsights: false,
|
secretAccessInsights: false,
|
||||||
auditLogs: false,
|
auditLogs: false,
|
||||||
|
|||||||
@@ -9,12 +9,12 @@ import { AxiosError } from "axios";
|
|||||||
import { CronJob } from "cron";
|
import { CronJob } from "cron";
|
||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
import { TKeyStoreFactory } from "@app/keystore/keystore";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { verifyOfflineLicense } from "@app/lib/crypto";
|
import { verifyOfflineLicense } from "@app/lib/crypto";
|
||||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
import { TIdentityOrgDALFactory } from "@app/services/identity/identity-org-dal";
|
|
||||||
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
||||||
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
import { TProjectDALFactory } from "@app/services/project/project-dal";
|
||||||
|
|
||||||
@@ -45,11 +45,10 @@ import {
|
|||||||
} from "./license-types";
|
} from "./license-types";
|
||||||
|
|
||||||
type TLicenseServiceFactoryDep = {
|
type TLicenseServiceFactoryDep = {
|
||||||
orgDAL: Pick<TOrgDALFactory, "findOrgById" | "countAllOrgMembers">;
|
orgDAL: Pick<TOrgDALFactory, "findRootOrgDetails" | "countAllOrgMembers" | "findById">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
licenseDAL: TLicenseDALFactory;
|
licenseDAL: TLicenseDALFactory;
|
||||||
keyStore: Pick<TKeyStoreFactory, "setItemWithExpiry" | "getItem" | "deleteItem">;
|
keyStore: Pick<TKeyStoreFactory, "setItemWithExpiry" | "getItem" | "deleteItem">;
|
||||||
identityOrgMembershipDAL: TIdentityOrgDALFactory;
|
|
||||||
projectDAL: TProjectDALFactory;
|
projectDAL: TProjectDALFactory;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -66,7 +65,6 @@ export const licenseServiceFactory = ({
|
|||||||
permissionService,
|
permissionService,
|
||||||
licenseDAL,
|
licenseDAL,
|
||||||
keyStore,
|
keyStore,
|
||||||
identityOrgMembershipDAL,
|
|
||||||
projectDAL
|
projectDAL
|
||||||
}: TLicenseServiceFactoryDep) => {
|
}: TLicenseServiceFactoryDep) => {
|
||||||
let isValidLicense = false;
|
let isValidLicense = false;
|
||||||
@@ -199,19 +197,21 @@ export const licenseServiceFactory = ({
|
|||||||
return JSON.parse(cachedPlan) as TFeatureSet;
|
return JSON.parse(cachedPlan) as TFeatureSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
const org = await orgDAL.findOrgById(orgId);
|
const org = await orgDAL.findRootOrgDetails(orgId);
|
||||||
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
|
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
|
||||||
|
const rootOrgId = org.id;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
data: { currentPlan }
|
data: { currentPlan }
|
||||||
} = await licenseServerCloudApi.request.get<{ currentPlan: TFeatureSet }>(
|
} = await licenseServerCloudApi.request.get<{ currentPlan: TFeatureSet }>(
|
||||||
`/api/license-server/v1/customers/${org.customerId}/cloud-plan`
|
`/api/license-server/v1/customers/${org.customerId}/cloud-plan`
|
||||||
);
|
);
|
||||||
const workspacesUsed = await projectDAL.countOfOrgProjects(orgId);
|
const workspacesUsed = await projectDAL.countOfOrgProjects(rootOrgId);
|
||||||
currentPlan.workspacesUsed = workspacesUsed;
|
currentPlan.workspacesUsed = workspacesUsed;
|
||||||
|
|
||||||
const membersUsed = await licenseDAL.countOfOrgMembers(orgId);
|
const membersUsed = await licenseDAL.countOfOrgMembers(rootOrgId);
|
||||||
currentPlan.membersUsed = membersUsed;
|
currentPlan.membersUsed = membersUsed;
|
||||||
const identityUsed = await licenseDAL.countOrgUsersAndIdentities(orgId);
|
const identityUsed = await licenseDAL.countOrgUsersAndIdentities(rootOrgId);
|
||||||
currentPlan.identitiesUsed = identityUsed;
|
currentPlan.identitiesUsed = identityUsed;
|
||||||
|
|
||||||
if (currentPlan.identityLimit && currentPlan.identityLimit !== identityUsed) {
|
if (currentPlan.identityLimit && currentPlan.identityLimit !== identityUsed) {
|
||||||
@@ -284,19 +284,20 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateSubscriptionOrgMemberCount = async (orgId: string, tx?: Knex) => {
|
const updateSubscriptionOrgMemberCount = async (orgId: string, tx?: Knex) => {
|
||||||
if (instanceType === InstanceType.Cloud) {
|
const org = await orgDAL.findRootOrgDetails(orgId, tx);
|
||||||
const org = await orgDAL.findOrgById(orgId);
|
|
||||||
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
|
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
|
||||||
|
|
||||||
const quantity = await licenseDAL.countOfOrgMembers(orgId, tx);
|
const rootOrgId = org.id;
|
||||||
const quantityIdentities = await licenseDAL.countOrgUsersAndIdentities(orgId, tx);
|
if (instanceType === InstanceType.Cloud) {
|
||||||
|
const quantity = await licenseDAL.countOfOrgMembers(rootOrgId, tx);
|
||||||
|
const quantityIdentities = await licenseDAL.countOrgUsersAndIdentities(rootOrgId, tx);
|
||||||
if (org?.customerId) {
|
if (org?.customerId) {
|
||||||
await licenseServerCloudApi.request.patch(`/api/license-server/v1/customers/${org.customerId}/cloud-plan`, {
|
await licenseServerCloudApi.request.patch(`/api/license-server/v1/customers/${org.customerId}/cloud-plan`, {
|
||||||
quantity,
|
quantity,
|
||||||
quantityIdentities
|
quantityIdentities
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await keyStore.deleteItem(FEATURE_CACHE_KEY(orgId));
|
await keyStore.deleteItem(FEATURE_CACHE_KEY(rootOrgId));
|
||||||
} else if (instanceType === InstanceType.EnterpriseOnPrem) {
|
} else if (instanceType === InstanceType.EnterpriseOnPrem) {
|
||||||
const usedSeats = await licenseDAL.countOfOrgMembers(null, tx);
|
const usedSeats = await licenseDAL.countOfOrgMembers(null, tx);
|
||||||
const usedIdentitySeats = await licenseDAL.countOrgUsersAndIdentities(null, tx);
|
const usedIdentitySeats = await licenseDAL.countOrgUsersAndIdentities(null, tx);
|
||||||
@@ -307,7 +308,7 @@ export const licenseServiceFactory = ({
|
|||||||
usedIdentitySeats
|
usedIdentitySeats
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
await refreshPlan(orgId);
|
await refreshPlan(rootOrgId);
|
||||||
};
|
};
|
||||||
|
|
||||||
// below all are api calls
|
// below all are api calls
|
||||||
@@ -319,7 +320,14 @@ export const licenseServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
billingCycle
|
billingCycle
|
||||||
}: TOrgPlansTableDTO) => {
|
}: TOrgPlansTableDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
||||||
const { data } = await licenseServerCloudApi.request.get(
|
const { data } = await licenseServerCloudApi.request.get(
|
||||||
`/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}`
|
`/api/license-server/v1/cloud-products?billing-cycle=${billingCycle}`
|
||||||
@@ -336,7 +344,14 @@ export const licenseServiceFactory = ({
|
|||||||
projectId,
|
projectId,
|
||||||
refreshCache
|
refreshCache
|
||||||
}: TOrgPlanDTO) => {
|
}: TOrgPlanDTO) => {
|
||||||
await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
if (refreshCache) {
|
if (refreshCache) {
|
||||||
await refreshPlan(orgId);
|
await refreshPlan(orgId);
|
||||||
}
|
}
|
||||||
@@ -352,13 +367,20 @@ export const licenseServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
success_url
|
success_url
|
||||||
}: TStartOrgTrialDTO) => {
|
}: TStartOrgTrialDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionBillingActions.ManageBilling,
|
OrgPermissionBillingActions.ManageBilling,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
);
|
);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -384,13 +406,20 @@ export const licenseServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TCreateOrgPortalSession) => {
|
}: TCreateOrgPortalSession) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionBillingActions.ManageBilling,
|
OrgPermissionBillingActions.ManageBilling,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
);
|
);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: "Organization not found"
|
message: "Organization not found"
|
||||||
@@ -433,10 +462,17 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getOrgBillingInfo = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TGetOrgBillInfoDTO) => {
|
const getOrgBillingInfo = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TGetOrgBillInfoDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -502,7 +538,7 @@ export const licenseServiceFactory = ({
|
|||||||
const getUsageMetrics = async (orgId: string) => {
|
const getUsageMetrics = async (orgId: string) => {
|
||||||
const [orgMembersUsed, identityUsed, projectCount] = await Promise.all([
|
const [orgMembersUsed, identityUsed, projectCount] = await Promise.all([
|
||||||
orgDAL.countAllOrgMembers(orgId),
|
orgDAL.countAllOrgMembers(orgId),
|
||||||
identityOrgMembershipDAL.countAllOrgIdentities({ scopeOrgId: orgId }),
|
licenseDAL.countOfOrgIdentities(orgId),
|
||||||
projectDAL.countOfOrgProjects(orgId)
|
projectDAL.countOfOrgProjects(orgId)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -516,10 +552,17 @@ export const licenseServiceFactory = ({
|
|||||||
|
|
||||||
// returns org current plan feature table
|
// returns org current plan feature table
|
||||||
const getOrgPlanTable = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TGetOrgBillInfoDTO) => {
|
const getOrgPlanTable = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TGetOrgBillInfoDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -553,10 +596,17 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getOrgBillingDetails = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TGetOrgBillInfoDTO) => {
|
const getOrgBillingDetails = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TGetOrgBillInfoDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -578,13 +628,20 @@ export const licenseServiceFactory = ({
|
|||||||
name,
|
name,
|
||||||
email
|
email
|
||||||
}: TUpdateOrgBillingDetailsDTO) => {
|
}: TUpdateOrgBillingDetailsDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionBillingActions.ManageBilling,
|
OrgPermissionBillingActions.ManageBilling,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
);
|
);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -601,10 +658,17 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getOrgPmtMethods = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TOrgPmtMethodsDTO) => {
|
const getOrgPmtMethods = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TOrgPmtMethodsDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -628,13 +692,20 @@ export const licenseServiceFactory = ({
|
|||||||
success_url,
|
success_url,
|
||||||
cancel_url
|
cancel_url
|
||||||
}: TAddOrgPmtMethodDTO) => {
|
}: TAddOrgPmtMethodDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionBillingActions.ManageBilling,
|
OrgPermissionBillingActions.ManageBilling,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
);
|
);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -660,13 +731,20 @@ export const licenseServiceFactory = ({
|
|||||||
orgId,
|
orgId,
|
||||||
pmtMethodId
|
pmtMethodId
|
||||||
}: TDelOrgPmtMethodDTO) => {
|
}: TDelOrgPmtMethodDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionBillingActions.ManageBilling,
|
OrgPermissionBillingActions.ManageBilling,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
);
|
);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -692,10 +770,17 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getOrgTaxIds = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TGetOrgTaxIdDTO) => {
|
const getOrgTaxIds = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TGetOrgTaxIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -710,13 +795,20 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const addOrgTaxId = async ({ actorId, actor, actorAuthMethod, actorOrgId, orgId, type, value }: TAddOrgTaxIdDTO) => {
|
const addOrgTaxId = async ({ actorId, actor, actorAuthMethod, actorOrgId, orgId, type, value }: TAddOrgTaxIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionBillingActions.ManageBilling,
|
OrgPermissionBillingActions.ManageBilling,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
);
|
);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -734,13 +826,20 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const delOrgTaxId = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId, taxId }: TDelOrgTaxIdDTO) => {
|
const delOrgTaxId = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId, taxId }: TDelOrgTaxIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionBillingActions.ManageBilling,
|
OrgPermissionBillingActions.ManageBilling,
|
||||||
OrgPermissionSubjects.Billing
|
OrgPermissionSubjects.Billing
|
||||||
);
|
);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -754,10 +853,17 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getOrgTaxInvoices = async ({ actorId, actor, actorOrgId, actorAuthMethod, orgId }: TOrgInvoiceDTO) => {
|
const getOrgTaxInvoices = async ({ actorId, actor, actorOrgId, actorAuthMethod, orgId }: TOrgInvoiceDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -771,10 +877,17 @@ export const licenseServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getOrgLicenses = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TOrgLicensesDTO) => {
|
const getOrgLicenses = async ({ orgId, actor, actorId, actorAuthMethod, actorOrgId }: TOrgLicensesDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId,
|
||||||
|
actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
|
||||||
|
|
||||||
const organization = await orgDAL.findOrgById(orgId);
|
const organization = await orgDAL.findById(orgId);
|
||||||
if (!organization) {
|
if (!organization) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with ID '${orgId}' not found`
|
message: `Organization with ID '${orgId}' not found`
|
||||||
@@ -819,7 +932,6 @@ export const licenseServiceFactory = ({
|
|||||||
getLicenseId,
|
getLicenseId,
|
||||||
invalidateGetPlan,
|
invalidateGetPlan,
|
||||||
updateSubscriptionOrgMemberCount,
|
updateSubscriptionOrgMemberCount,
|
||||||
refreshPlan,
|
|
||||||
getOrgPlan,
|
getOrgPlan,
|
||||||
getOrgPlansTableByBillCycle,
|
getOrgPlansTableByBillCycle,
|
||||||
startOrgTrial,
|
startOrgTrial,
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export type TFeatureSet = {
|
|||||||
membersUsed: number;
|
membersUsed: number;
|
||||||
identityLimit: null;
|
identityLimit: null;
|
||||||
identitiesUsed: number;
|
identitiesUsed: number;
|
||||||
|
subOrganization: false;
|
||||||
environmentLimit: null;
|
environmentLimit: null;
|
||||||
environmentsUsed: 0;
|
environmentsUsed: 0;
|
||||||
secretVersioning: true;
|
secretVersioning: true;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { Issuer, Issuer as OpenIdIssuer, Strategy as OpenIdStrategy, TokenSet } from "openid-client";
|
import { Issuer, Issuer as OpenIdIssuer, Strategy as OpenIdStrategy, TokenSet } from "openid-client";
|
||||||
|
|
||||||
import { AccessScope, OrgMembershipStatus, TableName, TUsers } from "@app/db/schemas";
|
import { AccessScope, OrganizationActionScope, OrgMembershipStatus, TableName, TUsers } from "@app/db/schemas";
|
||||||
import { TOidcConfigsUpdate } from "@app/db/schemas/oidc-configs";
|
import { TOidcConfigsUpdate } from "@app/db/schemas/oidc-configs";
|
||||||
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
|
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
|
||||||
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
import { TGroupDALFactory } from "@app/ee/services/group/group-dal";
|
||||||
@@ -118,13 +118,14 @@ export const oidcConfigServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dto.type === "external") {
|
if (dto.type === "external") {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.actor,
|
actorId: dto.actorId,
|
||||||
dto.actorId,
|
actor: dto.actor,
|
||||||
dto.organizationId,
|
orgId: dto.organizationId,
|
||||||
dto.actorAuthMethod,
|
actorOrgId: dto.actorOrgId,
|
||||||
dto.actorOrgId
|
actorAuthMethod: dto.actorAuthMethod,
|
||||||
);
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -508,13 +509,14 @@ export const oidcConfigServiceFactory = ({
|
|||||||
"Failed to update OIDC SSO configuration due to plan restriction. Upgrade plan to update SSO configuration."
|
"Failed to update OIDC SSO configuration due to plan restriction. Upgrade plan to update SSO configuration."
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
|
||||||
actorId,
|
actorId,
|
||||||
org.id,
|
actor,
|
||||||
|
orgId: org.id,
|
||||||
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
|
||||||
|
|
||||||
if (org.googleSsoAuthEnforced && isActive) {
|
if (org.googleSsoAuthEnforced && isActive) {
|
||||||
@@ -602,13 +604,14 @@ export const oidcConfigServiceFactory = ({
|
|||||||
"Failed to create OIDC SSO configuration due to plan restriction. Upgrade plan to update SSO configuration."
|
"Failed to create OIDC SSO configuration due to plan restriction. Upgrade plan to update SSO configuration."
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
|
||||||
actorId,
|
actorId,
|
||||||
org.id,
|
actor,
|
||||||
|
orgId: org.id,
|
||||||
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso);
|
||||||
|
|
||||||
if (org.googleSsoAuthEnforced && isActive) {
|
if (org.googleSsoAuthEnforced && isActive) {
|
||||||
@@ -764,7 +767,14 @@ export const oidcConfigServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const isOidcManageGroupMembershipsEnabled = async (orgId: string, actor: OrgServiceActor) => {
|
const isOidcManageGroupMembershipsEnabled = async (orgId: string, actor: OrgServiceActor) => {
|
||||||
await permissionService.getOrgPermission(ActorType.USER, actor.id, orgId, actor.authMethod, actor.orgId);
|
await permissionService.getOrgPermission({
|
||||||
|
actor: ActorType.USER,
|
||||||
|
actorId: actor.id,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod: actor.authMethod,
|
||||||
|
actorOrgId: actor.orgId,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
|
|
||||||
const oidcConfig = await oidcConfigDAL.findOne({
|
const oidcConfig = await oidcConfigDAL.findOne({
|
||||||
orgId,
|
orgId,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError, subject } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
|
|
||||||
import { ActionProjectType, TPamAccounts, TPamResources } from "@app/db/schemas";
|
import { ActionProjectType, OrganizationActionScope, TPamAccounts, TPamResources } from "@app/db/schemas";
|
||||||
import { PAM_RESOURCE_FACTORY_MAP } from "@app/ee/services/pam-resource/pam-resource-factory";
|
import { PAM_RESOURCE_FACTORY_MAP } from "@app/ee/services/pam-resource/pam-resource-factory";
|
||||||
import { decryptResource, decryptResourceConnectionDetails } from "@app/ee/services/pam-resource/pam-resource-fns";
|
import { decryptResource, decryptResourceConnectionDetails } from "@app/ee/services/pam-resource/pam-resource-fns";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
@@ -459,13 +459,14 @@ export const pamAccountServiceFactory = ({
|
|||||||
const project = await projectDAL.findById(session.projectId);
|
const project = await projectDAL.findById(session.projectId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with ID '${session.projectId}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with ID '${session.projectId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
project.orgId,
|
orgId: project.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.CreateGateways,
|
OrgPermissionGatewayActions.CreateGateways,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { ActionProjectType } from "@app/db/schemas";
|
import { ActionProjectType, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
import { OrgServiceActor } from "@app/lib/types";
|
import { OrgServiceActor } from "@app/lib/types";
|
||||||
@@ -102,13 +102,14 @@ export const pamSessionServiceFactory = ({
|
|||||||
const project = await projectDAL.findById(session.projectId);
|
const project = await projectDAL.findById(session.projectId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with ID '${session.projectId}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with ID '${session.projectId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
project.orgId,
|
orgId: project.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.CreateGateways,
|
OrgPermissionGatewayActions.CreateGateways,
|
||||||
@@ -142,13 +143,14 @@ export const pamSessionServiceFactory = ({
|
|||||||
const project = await projectDAL.findById(session.projectId);
|
const project = await projectDAL.findById(session.projectId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with ID '${session.projectId}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with ID '${session.projectId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
project.orgId,
|
orgId: project.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (actor.type === ActorType.IDENTITY) {
|
if (actor.type === ActorType.IDENTITY) {
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
|||||||
@@ -15,6 +15,11 @@ export enum OrgPermissionActions {
|
|||||||
Delete = "delete"
|
Delete = "delete"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum OrgPermissionSubOrgActions {
|
||||||
|
Create = "create",
|
||||||
|
DirectAccess = "direct-access"
|
||||||
|
}
|
||||||
|
|
||||||
export enum OrgPermissionAppConnectionActions {
|
export enum OrgPermissionAppConnectionActions {
|
||||||
Read = "read",
|
Read = "read",
|
||||||
Create = "create",
|
Create = "create",
|
||||||
@@ -117,7 +122,8 @@ export enum OrgPermissionSubjects {
|
|||||||
Kmip = "kmip",
|
Kmip = "kmip",
|
||||||
Gateway = "gateway",
|
Gateway = "gateway",
|
||||||
Relay = "relay",
|
Relay = "relay",
|
||||||
SecretShare = "secret-share"
|
SecretShare = "secret-share",
|
||||||
|
SubOrganization = "sub-organization"
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AppConnectionSubjectFields = {
|
export type AppConnectionSubjectFields = {
|
||||||
@@ -128,6 +134,7 @@ export type OrgPermissionSet =
|
|||||||
| [OrgPermissionActions.Create, OrgPermissionSubjects.Workspace]
|
| [OrgPermissionActions.Create, OrgPermissionSubjects.Workspace]
|
||||||
| [OrgPermissionActions.Create, OrgPermissionSubjects.Project]
|
| [OrgPermissionActions.Create, OrgPermissionSubjects.Project]
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.Role]
|
| [OrgPermissionActions, OrgPermissionSubjects.Role]
|
||||||
|
| [OrgPermissionSubOrgActions, OrgPermissionSubjects.SubOrganization]
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.Member]
|
| [OrgPermissionActions, OrgPermissionSubjects.Member]
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.Settings]
|
| [OrgPermissionActions, OrgPermissionSubjects.Settings]
|
||||||
| [OrgPermissionActions, OrgPermissionSubjects.IncidentAccount]
|
| [OrgPermissionActions, OrgPermissionSubjects.IncidentAccount]
|
||||||
@@ -185,6 +192,12 @@ export const OrgPermissionSchema = z.discriminatedUnion("subject", [
|
|||||||
subject: z.literal(OrgPermissionSubjects.Role).describe("The entity this permission pertains to."),
|
subject: z.literal(OrgPermissionSubjects.Role).describe("The entity this permission pertains to."),
|
||||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionActions).describe("Describe what action an entity can take.")
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionActions).describe("Describe what action an entity can take.")
|
||||||
}),
|
}),
|
||||||
|
z.object({
|
||||||
|
subject: z.literal(OrgPermissionSubjects.SubOrganization).describe("The entity this permission pertains to."),
|
||||||
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionSubOrgActions).describe(
|
||||||
|
"Describe what action an entity can take."
|
||||||
|
)
|
||||||
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
subject: z.literal(OrgPermissionSubjects.Member).describe("The entity this permission pertains to."),
|
subject: z.literal(OrgPermissionSubjects.Member).describe("The entity this permission pertains to."),
|
||||||
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionActions).describe("Describe what action an entity can take.")
|
action: CASL_ACTION_SCHEMA_NATIVE_ENUM(OrgPermissionActions).describe("Describe what action an entity can take.")
|
||||||
@@ -308,6 +321,10 @@ const buildAdminPermission = () => {
|
|||||||
// ws permissions
|
// ws permissions
|
||||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace);
|
can(OrgPermissionActions.Create, OrgPermissionSubjects.Workspace);
|
||||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.Project);
|
can(OrgPermissionActions.Create, OrgPermissionSubjects.Project);
|
||||||
|
|
||||||
|
can(OrgPermissionSubOrgActions.Create, OrgPermissionSubjects.SubOrganization);
|
||||||
|
can(OrgPermissionSubOrgActions.DirectAccess, OrgPermissionSubjects.SubOrganization);
|
||||||
|
|
||||||
// role permission
|
// role permission
|
||||||
can(OrgPermissionActions.Read, OrgPermissionSubjects.Role);
|
can(OrgPermissionActions.Read, OrgPermissionSubjects.Role);
|
||||||
can(OrgPermissionActions.Create, OrgPermissionSubjects.Role);
|
can(OrgPermissionActions.Create, OrgPermissionSubjects.Role);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ interface TPermissionDataReturn extends TMemberships {
|
|||||||
orgAuthEnforced?: boolean | null;
|
orgAuthEnforced?: boolean | null;
|
||||||
orgGoogleSsoAuthEnforced?: boolean | null;
|
orgGoogleSsoAuthEnforced?: boolean | null;
|
||||||
shouldUseNewPrivilegeSystem?: boolean | null;
|
shouldUseNewPrivilegeSystem?: boolean | null;
|
||||||
|
rootOrgId?: string | null;
|
||||||
bypassOrgAuthEnabled?: boolean | null;
|
bypassOrgAuthEnabled?: boolean | null;
|
||||||
roles: {
|
roles: {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -273,7 +274,8 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
|
|||||||
db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization),
|
db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization),
|
||||||
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
|
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
|
||||||
db.ref("googleSsoAuthEnforced").withSchema(TableName.Organization).as("orgGoogleSsoAuthEnforced"),
|
db.ref("googleSsoAuthEnforced").withSchema(TableName.Organization).as("orgGoogleSsoAuthEnforced"),
|
||||||
db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled")
|
db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled"),
|
||||||
|
db.ref("rootOrgId").withSchema(TableName.Organization).as("rootOrgId")
|
||||||
);
|
);
|
||||||
|
|
||||||
const data = sqlNestRelationships({
|
const data = sqlNestRelationships({
|
||||||
@@ -283,6 +285,7 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
|
|||||||
MembershipsSchema.extend({
|
MembershipsSchema.extend({
|
||||||
orgAuthEnforced: z.boolean().optional().nullable(),
|
orgAuthEnforced: z.boolean().optional().nullable(),
|
||||||
shouldUseNewPrivilegeSystem: z.boolean().optional().nullable(),
|
shouldUseNewPrivilegeSystem: z.boolean().optional().nullable(),
|
||||||
|
rootOrgId: z.string().optional().nullable(),
|
||||||
orgGoogleSsoAuthEnforced: z.boolean(),
|
orgGoogleSsoAuthEnforced: z.boolean(),
|
||||||
bypassOrgAuthEnabled: z.boolean()
|
bypassOrgAuthEnabled: z.boolean()
|
||||||
}).parse(el),
|
}).parse(el),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { MongoAbility } from "@casl/ability";
|
|||||||
import { MongoQuery } from "@ucast/mongo2js";
|
import { MongoQuery } from "@ucast/mongo2js";
|
||||||
import { Knex } from "knex";
|
import { Knex } from "knex";
|
||||||
|
|
||||||
import { ActionProjectType, TMemberships } from "@app/db/schemas";
|
import { ActionProjectType, OrganizationActionScope, TMemberships } from "@app/db/schemas";
|
||||||
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
import { ActorAuthMethod, ActorType } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
import { OrgPermissionSet } from "./org-permission";
|
import { OrgPermissionSet } from "./org-permission";
|
||||||
@@ -18,21 +18,6 @@ export type TBuildOrgPermissionDTO = {
|
|||||||
role: string;
|
role: string;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
export type TGetUserProjectPermissionArg = {
|
|
||||||
userId: string;
|
|
||||||
projectId: string;
|
|
||||||
authMethod: ActorAuthMethod;
|
|
||||||
actionProjectType: ActionProjectType;
|
|
||||||
userOrgId?: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TGetIdentityProjectPermissionArg = {
|
|
||||||
identityId: string;
|
|
||||||
projectId: string;
|
|
||||||
identityOrgId?: string;
|
|
||||||
actionProjectType: ActionProjectType;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type TGetServiceTokenProjectPermissionArg = {
|
export type TGetServiceTokenProjectPermissionArg = {
|
||||||
serviceTokenId: string;
|
serviceTokenId: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
@@ -54,17 +39,12 @@ export type TGetOrgPermissionArg = {
|
|||||||
actorId: string;
|
actorId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
actorAuthMethod: ActorAuthMethod;
|
actorAuthMethod: ActorAuthMethod;
|
||||||
actorOrgId?: string;
|
actorOrgId: string;
|
||||||
|
scope: OrganizationActionScope;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TPermissionServiceFactory = {
|
export type TPermissionServiceFactory = {
|
||||||
getOrgPermission: (
|
getOrgPermission: (arg: TGetOrgPermissionArg) => Promise<{
|
||||||
type: ActorType,
|
|
||||||
id: string,
|
|
||||||
orgId: string,
|
|
||||||
authMethod: ActorAuthMethod,
|
|
||||||
actorOrgId: string | undefined
|
|
||||||
) => Promise<{
|
|
||||||
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
permission: MongoAbility<OrgPermissionSet, MongoQuery>;
|
||||||
memberships: Array<
|
memberships: Array<
|
||||||
TMemberships & {
|
TMemberships & {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { Knex } from "knex";
|
|||||||
import {
|
import {
|
||||||
AccessScope,
|
AccessScope,
|
||||||
ActionProjectType,
|
ActionProjectType,
|
||||||
|
OrganizationActionScope,
|
||||||
OrgMembershipRole,
|
OrgMembershipRole,
|
||||||
ProjectMembershipRole,
|
ProjectMembershipRole,
|
||||||
ServiceTokenScopes
|
ServiceTokenScopes
|
||||||
@@ -179,14 +180,15 @@ export const permissionServiceFactory = ({
|
|||||||
// return minTtl;
|
// return minTtl;
|
||||||
// };
|
// };
|
||||||
|
|
||||||
const getOrgPermission: TPermissionServiceFactory["getOrgPermission"] = async (
|
const getOrgPermission: TPermissionServiceFactory["getOrgPermission"] = async ({
|
||||||
type,
|
actor,
|
||||||
id,
|
actorId,
|
||||||
orgId,
|
orgId,
|
||||||
authMethod,
|
actorOrgId,
|
||||||
actorOrgId
|
scope,
|
||||||
) => {
|
actorAuthMethod
|
||||||
if (type !== ActorType.USER && type !== ActorType.IDENTITY) {
|
}) => {
|
||||||
|
if (actor !== ActorType.USER && actor !== ActorType.IDENTITY) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Invalid actor provided",
|
message: "Invalid actor provided",
|
||||||
name: "Get org permission"
|
name: "Get org permission"
|
||||||
@@ -202,11 +204,19 @@ export const permissionServiceFactory = ({
|
|||||||
scope: AccessScope.Organization,
|
scope: AccessScope.Organization,
|
||||||
orgId
|
orgId
|
||||||
},
|
},
|
||||||
actorId: id,
|
actorId,
|
||||||
actorType: type
|
actorType: actor
|
||||||
});
|
});
|
||||||
if (!permissionData?.length) throw new ForbiddenRequestError({ name: "You are not member of this organization" });
|
if (!permissionData?.length) throw new ForbiddenRequestError({ name: "You are not member of this organization" });
|
||||||
|
|
||||||
|
const rootOrgId = permissionData?.[0]?.rootOrgId;
|
||||||
|
const isChild = Boolean(rootOrgId);
|
||||||
|
if (scope === OrganizationActionScope.ParentOrganization && isChild) {
|
||||||
|
throw new ForbiddenRequestError({ message: `Child organization cannot do this operation` });
|
||||||
|
} else if (scope === OrganizationActionScope.ChildOrganization && !isChild) {
|
||||||
|
throw new ForbiddenRequestError({ message: `Parent organization cannot do this operation` });
|
||||||
|
}
|
||||||
|
|
||||||
const permissionFromRoles = permissionData.flatMap((membership) => {
|
const permissionFromRoles = permissionData.flatMap((membership) => {
|
||||||
const activeRoles = membership?.roles
|
const activeRoles = membership?.roles
|
||||||
.filter(
|
.filter(
|
||||||
@@ -227,7 +237,7 @@ export const permissionServiceFactory = ({
|
|||||||
permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role)));
|
permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role)));
|
||||||
|
|
||||||
validateOrgSSO(
|
validateOrgSSO(
|
||||||
authMethod,
|
actorAuthMethod,
|
||||||
permissionData?.[0].orgAuthEnforced,
|
permissionData?.[0].orgAuthEnforced,
|
||||||
Boolean(permissionData?.[0].orgGoogleSsoAuthEnforced),
|
Boolean(permissionData?.[0].orgGoogleSsoAuthEnforced),
|
||||||
Boolean(permissionData?.[0].bypassOrgAuthEnabled),
|
Boolean(permissionData?.[0].bypassOrgAuthEnabled),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { packRules } from "@casl/ability/extra";
|
import { packRules } from "@casl/ability/extra";
|
||||||
|
|
||||||
import { ProjectType, TProjectTemplates } from "@app/db/schemas";
|
import { OrganizationActionScope, ProjectType, TProjectTemplates } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
@@ -59,13 +59,14 @@ export const projectTemplateServiceFactory = ({
|
|||||||
message: "Failed to access project templates due to plan restriction. Upgrade plan to access project templates."
|
message: "Failed to access project templates due to plan restriction. Upgrade plan to access project templates."
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
|
||||||
|
|
||||||
@@ -97,13 +98,14 @@ export const projectTemplateServiceFactory = ({
|
|||||||
|
|
||||||
if (!projectTemplate) throw new NotFoundError({ message: `Could not find project template with Name "${name}"` });
|
if (!projectTemplate) throw new NotFoundError({ message: `Could not find project template with Name "${name}"` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
projectTemplate.orgId,
|
orgId: projectTemplate.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
|
||||||
|
|
||||||
@@ -125,13 +127,14 @@ export const projectTemplateServiceFactory = ({
|
|||||||
|
|
||||||
if (!projectTemplate) throw new NotFoundError({ message: `Could not find project template with ID ${id}` });
|
if (!projectTemplate) throw new NotFoundError({ message: `Could not find project template with ID ${id}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
projectTemplate.orgId,
|
orgId: projectTemplate.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.ProjectTemplates);
|
||||||
|
|
||||||
@@ -152,13 +155,14 @@ export const projectTemplateServiceFactory = ({
|
|||||||
message: "Failed to create project template due to plan restriction. Upgrade plan to access project templates."
|
message: "Failed to create project template due to plan restriction. Upgrade plan to access project templates."
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.ProjectTemplates);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.ProjectTemplates);
|
||||||
|
|
||||||
@@ -213,13 +217,14 @@ export const projectTemplateServiceFactory = ({
|
|||||||
|
|
||||||
if (!projectTemplate) throw new NotFoundError({ message: `Could not find project template with ID ${id}` });
|
if (!projectTemplate) throw new NotFoundError({ message: `Could not find project template with ID ${id}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
projectTemplate.orgId,
|
orgId: projectTemplate.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.ProjectTemplates);
|
||||||
if (projectTemplate.type !== ProjectType.SecretManager && environments)
|
if (projectTemplate.type !== ProjectType.SecretManager && environments)
|
||||||
@@ -272,13 +277,14 @@ export const projectTemplateServiceFactory = ({
|
|||||||
|
|
||||||
if (!projectTemplate) throw new NotFoundError({ message: `Could not find project template with ID ${id}` });
|
if (!projectTemplate) throw new NotFoundError({ message: `Could not find project template with ID ${id}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
projectTemplate.orgId,
|
orgId: projectTemplate.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.ProjectTemplates);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.ProjectTemplates);
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { ProjectMembershipRole, ProjectType, TProjectEnvironments } from "@app/db/schemas";
|
import { ProjectMembershipRole, ProjectType, TProjectEnvironments } from "@app/db/schemas";
|
||||||
import { TProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
import { TProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission";
|
||||||
import { OrgServiceActor } from "@app/lib/types";
|
import { ProjectServiceActor } from "@app/lib/types";
|
||||||
import { UnpackedPermissionSchema } from "@app/server/routes/sanitizedSchema/permission";
|
import { UnpackedPermissionSchema } from "@app/server/routes/sanitizedSchema/permission";
|
||||||
|
|
||||||
export type TProjectTemplateEnvironment = Pick<TProjectEnvironments, "name" | "slug" | "position">;
|
export type TProjectTemplateEnvironment = Pick<TProjectEnvironments, "name" | "slug" | "position">;
|
||||||
@@ -31,7 +31,7 @@ export enum InfisicalProjectTemplate {
|
|||||||
|
|
||||||
export type TProjectTemplateServiceFactory = {
|
export type TProjectTemplateServiceFactory = {
|
||||||
listProjectTemplatesByOrg: (
|
listProjectTemplatesByOrg: (
|
||||||
actor: OrgServiceActor,
|
actor: ProjectServiceActor,
|
||||||
type?: ProjectType
|
type?: ProjectType
|
||||||
) => Promise<
|
) => Promise<
|
||||||
(
|
(
|
||||||
@@ -85,7 +85,7 @@ export type TProjectTemplateServiceFactory = {
|
|||||||
>;
|
>;
|
||||||
createProjectTemplate: (
|
createProjectTemplate: (
|
||||||
arg: TCreateProjectTemplateDTO,
|
arg: TCreateProjectTemplateDTO,
|
||||||
actor: OrgServiceActor
|
actor: ProjectServiceActor
|
||||||
) => Promise<{
|
) => Promise<{
|
||||||
environments: TProjectTemplateEnvironment[];
|
environments: TProjectTemplateEnvironment[];
|
||||||
roles: {
|
roles: {
|
||||||
@@ -109,7 +109,7 @@ export type TProjectTemplateServiceFactory = {
|
|||||||
updateProjectTemplateById: (
|
updateProjectTemplateById: (
|
||||||
id: string,
|
id: string,
|
||||||
{ roles, environments, ...params }: TUpdateProjectTemplateDTO,
|
{ roles, environments, ...params }: TUpdateProjectTemplateDTO,
|
||||||
actor: OrgServiceActor
|
actor: ProjectServiceActor
|
||||||
) => Promise<{
|
) => Promise<{
|
||||||
environments: TProjectTemplateEnvironment[];
|
environments: TProjectTemplateEnvironment[];
|
||||||
roles: {
|
roles: {
|
||||||
@@ -132,7 +132,7 @@ export type TProjectTemplateServiceFactory = {
|
|||||||
}>;
|
}>;
|
||||||
deleteProjectTemplateById: (
|
deleteProjectTemplateById: (
|
||||||
id: string,
|
id: string,
|
||||||
actor: OrgServiceActor
|
actor: ProjectServiceActor
|
||||||
) => Promise<{
|
) => Promise<{
|
||||||
environments: TProjectTemplateEnvironment[];
|
environments: TProjectTemplateEnvironment[];
|
||||||
roles: {
|
roles: {
|
||||||
@@ -155,7 +155,7 @@ export type TProjectTemplateServiceFactory = {
|
|||||||
}>;
|
}>;
|
||||||
findProjectTemplateById: (
|
findProjectTemplateById: (
|
||||||
id: string,
|
id: string,
|
||||||
actor: OrgServiceActor
|
actor: ProjectServiceActor
|
||||||
) => Promise<{
|
) => Promise<{
|
||||||
packedRoles: TProjectTemplateRole[];
|
packedRoles: TProjectTemplateRole[];
|
||||||
environments: TProjectTemplateEnvironment[];
|
environments: TProjectTemplateEnvironment[];
|
||||||
@@ -179,7 +179,7 @@ export type TProjectTemplateServiceFactory = {
|
|||||||
}>;
|
}>;
|
||||||
findProjectTemplateByName: (
|
findProjectTemplateByName: (
|
||||||
name: string,
|
name: string,
|
||||||
actor: OrgServiceActor
|
actor: ProjectServiceActor
|
||||||
) => Promise<{
|
) => Promise<{
|
||||||
packedRoles: TProjectTemplateRole[];
|
packedRoles: TProjectTemplateRole[];
|
||||||
environments: TProjectTemplateEnvironment[];
|
environments: TProjectTemplateEnvironment[];
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { isIP } from "node:net";
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import * as x509 from "@peculiar/x509";
|
import * as x509 from "@peculiar/x509";
|
||||||
|
|
||||||
import { OrgMembershipRole, TRelays } from "@app/db/schemas";
|
import { OrganizationActionScope, OrgMembershipRole, TRelays } from "@app/db/schemas";
|
||||||
import { PgSqlLock } from "@app/keystore/keystore";
|
import { PgSqlLock } from "@app/keystore/keystore";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError } from "@app/lib/errors";
|
||||||
@@ -126,8 +126,8 @@ export const relayServiceFactory = ({
|
|||||||
|
|
||||||
// generate instance relay CA
|
// generate instance relay CA
|
||||||
const instanceRelayCaSerialNumber = createSerialNumber();
|
const instanceRelayCaSerialNumber = createSerialNumber();
|
||||||
const instanceRelayCaIssuedAt = new Date();
|
|
||||||
const instanceRelayCaExpiration = new Date(new Date().setFullYear(2045));
|
const instanceRelayCaExpiration = new Date(new Date().setFullYear(2045));
|
||||||
|
const instanceRelayCaIssuedAt = new Date();
|
||||||
const instanceRelayCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
const instanceRelayCaKeys = await crypto.nativeCrypto.subtle.generateKey(alg, true, ["sign", "verify"]);
|
||||||
const instanceRelayCaSkObj = crypto.nativeCrypto.KeyObject.from(instanceRelayCaKeys.privateKey);
|
const instanceRelayCaSkObj = crypto.nativeCrypto.KeyObject.from(instanceRelayCaKeys.privateKey);
|
||||||
const instanceRelayCaCert = await x509.X509CertificateGenerator.create({
|
const instanceRelayCaCert = await x509.X509CertificateGenerator.create({
|
||||||
@@ -972,13 +972,14 @@ export const relayServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
scope: OrganizationActionScope.Any,
|
||||||
identityId,
|
actor: ActorType.IDENTITY,
|
||||||
|
actorId: identityId,
|
||||||
orgId,
|
orgId,
|
||||||
actorAuthMethod!,
|
actorAuthMethod: actorAuthMethod!,
|
||||||
orgId
|
actorOrgId: orgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionRelayActions.CreateRelays,
|
OrgPermissionRelayActions.CreateRelays,
|
||||||
@@ -1102,13 +1103,14 @@ export const relayServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
scope: OrganizationActionScope.Any,
|
||||||
identityId,
|
actor: ActorType.IDENTITY,
|
||||||
|
actorId: identityId,
|
||||||
orgId,
|
orgId,
|
||||||
actorAuthMethod!,
|
actorAuthMethod: actorAuthMethod!,
|
||||||
orgId
|
actorOrgId: orgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionRelayActions.CreateRelays,
|
OrgPermissionRelayActions.CreateRelays,
|
||||||
OrgPermissionSubjects.Relay
|
OrgPermissionSubjects.Relay
|
||||||
@@ -1155,13 +1157,14 @@ export const relayServiceFactory = ({
|
|||||||
actorAuthMethod: ActorAuthMethod;
|
actorAuthMethod: ActorAuthMethod;
|
||||||
actorOrgId: string;
|
actorOrgId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod: actorAuthMethod!,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionRelayActions.ListRelays, OrgPermissionSubjects.Relay);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionRelayActions.ListRelays, OrgPermissionSubjects.Relay);
|
||||||
|
|
||||||
@@ -1189,13 +1192,14 @@ export const relayServiceFactory = ({
|
|||||||
actorAuthMethod: ActorAuthMethod;
|
actorAuthMethod: ActorAuthMethod;
|
||||||
actorOrgId: string;
|
actorOrgId: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionRelayActions.DeleteRelays, OrgPermissionSubjects.Relay);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionRelayActions.DeleteRelays, OrgPermissionSubjects.Relay);
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import RE2 from "re2";
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AccessScope,
|
AccessScope,
|
||||||
|
OrganizationActionScope,
|
||||||
OrgMembershipRole,
|
OrgMembershipRole,
|
||||||
OrgMembershipStatus,
|
OrgMembershipStatus,
|
||||||
TableName,
|
TableName,
|
||||||
@@ -251,7 +252,14 @@ export const samlConfigServiceFactory = ({
|
|||||||
authProvider,
|
authProvider,
|
||||||
enableGroupSync
|
enableGroupSync
|
||||||
}) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Sso);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
@@ -317,7 +325,14 @@ export const samlConfigServiceFactory = ({
|
|||||||
authProvider,
|
authProvider,
|
||||||
enableGroupSync
|
enableGroupSync
|
||||||
}) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Sso);
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
if (!plan.samlSSO)
|
if (!plan.samlSSO)
|
||||||
@@ -393,7 +408,7 @@ export const samlConfigServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else if (dto.type === "orgSlug") {
|
} else if (dto.type === "orgSlug") {
|
||||||
const org = await orgDAL.findOne({ slug: dto.orgSlug });
|
const org = await orgDAL.findOne({ slug: dto.orgSlug, rootOrgId: null });
|
||||||
if (!org) {
|
if (!org) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
message: `Organization with slug '${dto.orgSlug}' not found`
|
message: `Organization with slug '${dto.orgSlug}' not found`
|
||||||
@@ -424,13 +439,14 @@ export const samlConfigServiceFactory = ({
|
|||||||
|
|
||||||
// when dto is type id means it's internally used
|
// when dto is type id means it's internally used
|
||||||
if (dto.type === "org") {
|
if (dto.type === "org") {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.actor,
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
dto.actorId,
|
actor: dto.actor,
|
||||||
samlConfig.orgId,
|
actorId: dto.actorId,
|
||||||
dto.actorAuthMethod,
|
orgId: samlConfig.orgId,
|
||||||
dto.actorOrgId
|
actorAuthMethod: dto.actorAuthMethod,
|
||||||
);
|
actorOrgId: dto.actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Sso);
|
||||||
}
|
}
|
||||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export type TGetSamlCfgDTO =
|
|||||||
actor: ActorType;
|
actor: ActorType;
|
||||||
actorId: string;
|
actorId: string;
|
||||||
actorAuthMethod: ActorAuthMethod;
|
actorAuthMethod: ActorAuthMethod;
|
||||||
actorOrgId: string | undefined;
|
actorOrgId: string;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: "orgSlug";
|
type: "orgSlug";
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { scimPatch } from "scim-patch";
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
AccessScope,
|
AccessScope,
|
||||||
|
OrganizationActionScope,
|
||||||
OrgMembershipRole,
|
OrgMembershipRole,
|
||||||
OrgMembershipStatus,
|
OrgMembershipStatus,
|
||||||
TableName,
|
TableName,
|
||||||
@@ -56,6 +57,7 @@ type TScimServiceFactoryDep = {
|
|||||||
TOrgDALFactory,
|
TOrgDALFactory,
|
||||||
| "createMembership"
|
| "createMembership"
|
||||||
| "findById"
|
| "findById"
|
||||||
|
| "find"
|
||||||
| "findMembership"
|
| "findMembership"
|
||||||
| "findMembershipWithScimFilter"
|
| "findMembershipWithScimFilter"
|
||||||
| "deleteMembershipById"
|
| "deleteMembershipById"
|
||||||
@@ -125,7 +127,14 @@ export const scimServiceFactory = ({
|
|||||||
description,
|
description,
|
||||||
ttlDays
|
ttlDays
|
||||||
}) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Scim);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Scim);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
@@ -160,7 +169,14 @@ export const scimServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
orgId
|
orgId
|
||||||
}) => {
|
}) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Scim);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Scim);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(orgId);
|
const plan = await licenseService.getPlan(orgId);
|
||||||
@@ -183,13 +199,14 @@ export const scimServiceFactory = ({
|
|||||||
let scimToken = await scimDAL.findById(scimTokenId);
|
let scimToken = await scimDAL.findById(scimTokenId);
|
||||||
if (!scimToken) throw new NotFoundError({ message: `SCIM token with ID '${scimTokenId}' not found` });
|
if (!scimToken) throw new NotFoundError({ message: `SCIM token with ID '${scimTokenId}' not found` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.ParentOrganization,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
scimToken.orgId,
|
orgId: scimToken.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Scim);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Scim);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(scimToken.orgId);
|
const plan = await licenseService.getPlan(scimToken.orgId);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import { WebhookEventMap } from "@octokit/webhooks-types";
|
import { WebhookEventMap } from "@octokit/webhooks-types";
|
||||||
import { ProbotOctokit } from "probot";
|
import { ProbotOctokit } from "probot";
|
||||||
|
|
||||||
|
import { OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
@@ -49,7 +50,14 @@ export const secretScanningServiceFactory = ({
|
|||||||
}: TInstallAppSessionDTO) => {
|
}: TInstallAppSessionDTO) => {
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
|
||||||
|
|
||||||
const sessionId = crypto.randomBytes(16).toString("hex");
|
const sessionId = crypto.randomBytes(16).toString("hex");
|
||||||
@@ -68,13 +76,14 @@ export const secretScanningServiceFactory = ({
|
|||||||
const session = await gitAppInstallSessionDAL.findOne({ sessionId });
|
const session = await gitAppInstallSessionDAL.findOne({ sessionId });
|
||||||
if (!session) throw new NotFoundError({ message: "Session was not found" });
|
if (!session) throw new NotFoundError({ message: "Session was not found" });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
session.orgId,
|
orgId: session.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.SecretScanning);
|
||||||
const installatedApp = await gitAppOrgDAL.transaction(async (tx) => {
|
const installatedApp = await gitAppOrgDAL.transaction(async (tx) => {
|
||||||
await gitAppInstallSessionDAL.deleteById(session.id, tx);
|
await gitAppInstallSessionDAL.deleteById(session.id, tx);
|
||||||
@@ -117,7 +126,14 @@ export const secretScanningServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
}: TGetOrgInstallStatusDTO) => {
|
}: TGetOrgInstallStatusDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
|
||||||
|
|
||||||
const appInstallation = await gitAppOrgDAL.findOne({ orgId });
|
const appInstallation = await gitAppOrgDAL.findOne({ orgId });
|
||||||
@@ -125,7 +141,14 @@ export const secretScanningServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getRisksByOrg = async ({ actor, orgId, actorId, actorAuthMethod, actorOrgId, filter }: TGetOrgRisksDTO) => {
|
const getRisksByOrg = async ({ actor, orgId, actorId, actorAuthMethod, actorOrgId, filter }: TGetOrgRisksDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
|
||||||
|
|
||||||
const results = await secretScanningDAL.findByOrgId(orgId, filter);
|
const results = await secretScanningDAL.findByOrgId(orgId, filter);
|
||||||
@@ -134,7 +157,14 @@ export const secretScanningServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getAllRisksByOrg = async ({ actor, orgId, actorId, actorAuthMethod, actorOrgId }: TGetAllOrgRisksDTO) => {
|
const getAllRisksByOrg = async ({ actor, orgId, actorId, actorAuthMethod, actorOrgId }: TGetAllOrgRisksDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.SecretScanning);
|
||||||
|
|
||||||
const risks = await secretScanningDAL.find({ orgId }, { sort: [["createdAt", "desc"]] });
|
const risks = await secretScanningDAL.find({ orgId }, { sort: [["createdAt", "desc"]] });
|
||||||
@@ -150,7 +180,14 @@ export const secretScanningServiceFactory = ({
|
|||||||
riskId,
|
riskId,
|
||||||
status
|
status
|
||||||
}: TUpdateRiskStatusDTO) => {
|
}: TUpdateRiskStatusDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.SecretScanning);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.SecretScanning);
|
||||||
|
|
||||||
const isRiskResolved = Boolean(
|
const isRiskResolved = Boolean(
|
||||||
|
|||||||
@@ -0,0 +1,160 @@
|
|||||||
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
|
import { AccessScope, OrganizationActionScope, OrgMembershipRole, OrgMembershipStatus } from "@app/db/schemas";
|
||||||
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { ActorType } from "@app/services/auth/auth-type";
|
||||||
|
import { TMembershipDALFactory } from "@app/services/membership/membership-dal";
|
||||||
|
import { TMembershipRoleDALFactory } from "@app/services/membership/membership-role-dal";
|
||||||
|
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
||||||
|
|
||||||
|
import { TLicenseServiceFactory } from "../license/license-service";
|
||||||
|
import { OrgPermissionActions, OrgPermissionSubjects, OrgPermissionSubOrgActions } from "../permission/org-permission";
|
||||||
|
import { TPermissionServiceFactory } from "../permission/permission-service-types";
|
||||||
|
import { TCreateSubOrgDTO, TListSubOrgDTO, TUpdateSubOrgDTO } from "./sub-org-types";
|
||||||
|
|
||||||
|
type TSubOrgServiceFactoryDep = {
|
||||||
|
orgDAL: Pick<
|
||||||
|
TOrgDALFactory,
|
||||||
|
"findOne" | "create" | "transaction" | "listSubOrganizations" | "updateById" | "findById"
|
||||||
|
>;
|
||||||
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
|
membershipDAL: Pick<TMembershipDALFactory, "create">;
|
||||||
|
membershipRoleDAL: Pick<TMembershipRoleDALFactory, "create">;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TSubOrgServiceFactory = ReturnType<typeof subOrgServiceFactory>;
|
||||||
|
|
||||||
|
export const subOrgServiceFactory = ({
|
||||||
|
orgDAL,
|
||||||
|
permissionService,
|
||||||
|
licenseService,
|
||||||
|
membershipDAL,
|
||||||
|
membershipRoleDAL
|
||||||
|
}: TSubOrgServiceFactoryDep) => {
|
||||||
|
const createSubOrg = async ({ name, permissionActor }: TCreateSubOrgDTO) => {
|
||||||
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId: permissionActor.id,
|
||||||
|
actor: permissionActor.type,
|
||||||
|
orgId: permissionActor.orgId,
|
||||||
|
actorOrgId: permissionActor.orgId,
|
||||||
|
actorAuthMethod: permissionActor.authMethod,
|
||||||
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
|
OrgPermissionSubOrgActions.Create,
|
||||||
|
OrgPermissionSubjects.SubOrganization
|
||||||
|
);
|
||||||
|
|
||||||
|
const orgLicensePlan = await licenseService.getPlan(permissionActor.rootOrgId);
|
||||||
|
if (!orgLicensePlan.subOrganization) {
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: "Sub-organization creation failed. Please upgrade your instance to Infisical's Enterprise plan."
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingSubOrg = await orgDAL.findOne({
|
||||||
|
parentOrgId: permissionActor.orgId,
|
||||||
|
name
|
||||||
|
});
|
||||||
|
if (existingSubOrg) {
|
||||||
|
throw new BadRequestError({ message: `Sub-organization with name ${name} already exists` });
|
||||||
|
}
|
||||||
|
|
||||||
|
const organization = await orgDAL.transaction(async (tx) => {
|
||||||
|
const org = await orgDAL.create(
|
||||||
|
{ name, slug: name, rootOrgId: permissionActor.rootOrgId, parentOrgId: permissionActor.orgId },
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
const membership = await membershipDAL.create(
|
||||||
|
{
|
||||||
|
scope: AccessScope.Organization,
|
||||||
|
[permissionActor.type === ActorType.IDENTITY ? "actorIdentityId" : "actorUserId"]: permissionActor.id,
|
||||||
|
scopeOrgId: org.id,
|
||||||
|
status: OrgMembershipStatus.Accepted,
|
||||||
|
isActive: true
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
await membershipRoleDAL.create(
|
||||||
|
{
|
||||||
|
membershipId: membership.id,
|
||||||
|
role: OrgMembershipRole.Admin
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
return org;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
organization
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const listSubOrgs = async ({ permissionActor, data }: TListSubOrgDTO) => {
|
||||||
|
await permissionService.getOrgPermission({
|
||||||
|
actorId: permissionActor.id,
|
||||||
|
actor: permissionActor.type,
|
||||||
|
orgId: permissionActor.rootOrgId,
|
||||||
|
actorOrgId: permissionActor.rootOrgId,
|
||||||
|
actorAuthMethod: permissionActor.authMethod,
|
||||||
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
|
const organizations = await orgDAL.listSubOrganizations({
|
||||||
|
actorId: permissionActor.id,
|
||||||
|
actorType: permissionActor.type,
|
||||||
|
orgId: permissionActor.rootOrgId,
|
||||||
|
isAccessible: data?.isAccessible,
|
||||||
|
limit: data?.limit,
|
||||||
|
offset: data?.offset
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
organizations
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateSubOrg = async ({ subOrgId, name, permissionActor }: TUpdateSubOrgDTO) => {
|
||||||
|
const subOrg = await orgDAL.findOne({
|
||||||
|
rootOrgId: permissionActor.rootOrgId,
|
||||||
|
id: subOrgId
|
||||||
|
});
|
||||||
|
if (!subOrg) {
|
||||||
|
throw new BadRequestError({ message: "Sub-organization not found" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actorId: permissionActor.id,
|
||||||
|
actor: permissionActor.type,
|
||||||
|
orgId: subOrgId,
|
||||||
|
actorOrgId: subOrgId,
|
||||||
|
actorAuthMethod: permissionActor.authMethod,
|
||||||
|
scope: OrganizationActionScope.ChildOrganization
|
||||||
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
|
const existingSubOrg = await orgDAL.findOne({
|
||||||
|
parentOrgId: subOrg.parentOrgId,
|
||||||
|
slug: name
|
||||||
|
});
|
||||||
|
|
||||||
|
if (existingSubOrg && existingSubOrg.id !== subOrgId) {
|
||||||
|
throw new BadRequestError({ message: `Sub-organization with name ${name} already exists` });
|
||||||
|
}
|
||||||
|
|
||||||
|
const organization = await orgDAL.updateById(subOrgId, { name, slug: name });
|
||||||
|
|
||||||
|
return {
|
||||||
|
organization
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
createSubOrg,
|
||||||
|
listSubOrgs,
|
||||||
|
updateSubOrg
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { OrgServiceActor } from "@app/lib/types";
|
||||||
|
|
||||||
|
export type TCreateSubOrgDTO = {
|
||||||
|
name: string;
|
||||||
|
permissionActor: OrgServiceActor;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TListSubOrgDTO = {
|
||||||
|
permissionActor: OrgServiceActor;
|
||||||
|
data: Partial<{
|
||||||
|
limit?: number;
|
||||||
|
offset?: number;
|
||||||
|
search?: string;
|
||||||
|
isAccessible?: boolean;
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type TUpdateSubOrgDTO = {
|
||||||
|
subOrgId: string;
|
||||||
|
name: string;
|
||||||
|
permissionActor: OrgServiceActor;
|
||||||
|
};
|
||||||
@@ -33,6 +33,7 @@ export enum ApiDocsTags {
|
|||||||
LdapAuth = "LDAP Auth",
|
LdapAuth = "LDAP Auth",
|
||||||
Groups = "Groups",
|
Groups = "Groups",
|
||||||
Organizations = "Organizations",
|
Organizations = "Organizations",
|
||||||
|
SubOrganizations = "Sub Organizations",
|
||||||
Projects = "Projects",
|
Projects = "Projects",
|
||||||
ProjectUsers = "Project Users",
|
ProjectUsers = "Project Users",
|
||||||
ProjectGroups = "Project Groups",
|
ProjectGroups = "Project Groups",
|
||||||
@@ -717,6 +718,21 @@ export const ORGANIZATIONS = {
|
|||||||
}
|
}
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
export const SUB_ORGANIZATIONS = {
|
||||||
|
CREATE: {
|
||||||
|
name: "The name of the sub organization to create."
|
||||||
|
},
|
||||||
|
UPDATE: {
|
||||||
|
name: "The name of the sub organization to update.",
|
||||||
|
subOrgId: "The id of the sub organization to update."
|
||||||
|
},
|
||||||
|
LIST: {
|
||||||
|
limit: "The number of sub organizations to return.",
|
||||||
|
offset: "The offset to start from. If you enter 10, it will start from the 10th sub organization.",
|
||||||
|
isAccessible: "Filter to only return sub organizations that the actor has access to."
|
||||||
|
}
|
||||||
|
} as const;
|
||||||
|
|
||||||
export const PROJECTS = {
|
export const PROJECTS = {
|
||||||
CREATE: {
|
CREATE: {
|
||||||
organizationSlug: "The slug of the organization to create the project in.",
|
organizationSlug: "The slug of the organization to create the project in.",
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ export type TGenericPermission = {
|
|||||||
actor: ActorType;
|
actor: ActorType;
|
||||||
actorId: string;
|
actorId: string;
|
||||||
actorAuthMethod: ActorAuthMethod;
|
actorAuthMethod: ActorAuthMethod;
|
||||||
actorOrgId: string | undefined;
|
actorOrgId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -78,6 +78,15 @@ export type OrgServiceActor = {
|
|||||||
id: string;
|
id: string;
|
||||||
authMethod: ActorAuthMethod;
|
authMethod: ActorAuthMethod;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
|
parentOrgId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ProjectServiceActor = {
|
||||||
|
type: ActorType;
|
||||||
|
id: string;
|
||||||
|
authMethod: ActorAuthMethod;
|
||||||
|
orgId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum QueueWorkerProfile {
|
export enum QueueWorkerProfile {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { TScimTokenJwtPayload } from "@app/ee/services/scim/scim-types";
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError } from "@app/lib/errors";
|
import { BadRequestError } from "@app/lib/errors";
|
||||||
|
import { slugSchema } from "@app/server/lib/schemas";
|
||||||
import { ActorType, AuthMethod, AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
|
import { ActorType, AuthMethod, AuthMode, AuthModeJwtTokenPayload, AuthTokenType } from "@app/services/auth/auth-type";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "@app/services/identity-access-token/identity-access-token-types";
|
||||||
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
import { getServerCfg } from "@app/services/super-admin/super-admin-service";
|
||||||
@@ -20,6 +21,8 @@ export type TAuthMode =
|
|||||||
tokenVersionId: string; // the session id of token used
|
tokenVersionId: string; // the session id of token used
|
||||||
user: TUsers;
|
user: TUsers;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
|
parentOrgId: string;
|
||||||
authMethod: AuthMethod;
|
authMethod: AuthMethod;
|
||||||
isMfaVerified?: boolean;
|
isMfaVerified?: boolean;
|
||||||
token: AuthModeJwtTokenPayload;
|
token: AuthModeJwtTokenPayload;
|
||||||
@@ -31,6 +34,8 @@ export type TAuthMode =
|
|||||||
userId: string;
|
userId: string;
|
||||||
user: TUsers;
|
user: TUsers;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
|
parentOrgId: string;
|
||||||
token: string;
|
token: string;
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
@@ -39,6 +44,8 @@ export type TAuthMode =
|
|||||||
actor: ActorType.SERVICE;
|
actor: ActorType.SERVICE;
|
||||||
serviceTokenId: string;
|
serviceTokenId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
|
parentOrgId: string;
|
||||||
authMethod: null;
|
authMethod: null;
|
||||||
token: string;
|
token: string;
|
||||||
}
|
}
|
||||||
@@ -48,6 +55,8 @@ export type TAuthMode =
|
|||||||
identityId: string;
|
identityId: string;
|
||||||
identityName: string;
|
identityName: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
|
parentOrgId: string;
|
||||||
authMethod: null;
|
authMethod: null;
|
||||||
isInstanceAdmin?: boolean;
|
isInstanceAdmin?: boolean;
|
||||||
token: TIdentityAccessTokenJwtPayload;
|
token: TIdentityAccessTokenJwtPayload;
|
||||||
@@ -57,6 +66,8 @@ export type TAuthMode =
|
|||||||
actor: ActorType.SCIM_CLIENT;
|
actor: ActorType.SCIM_CLIENT;
|
||||||
scimTokenId: string;
|
scimTokenId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
|
parentOrgId: string;
|
||||||
authMethod: null;
|
authMethod: null;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -136,17 +147,26 @@ export const injectIdentity = fp(
|
|||||||
|
|
||||||
if (!authMode) return;
|
if (!authMode) return;
|
||||||
|
|
||||||
|
const subOrganizationSelector = req.headers?.["x-infisical-org"] as string | undefined;
|
||||||
|
if (subOrganizationSelector) {
|
||||||
|
await slugSchema().parseAsync(subOrganizationSelector);
|
||||||
|
}
|
||||||
|
|
||||||
switch (authMode) {
|
switch (authMode) {
|
||||||
case AuthMode.JWT: {
|
case AuthMode.JWT: {
|
||||||
const { user, tokenVersionId, orgId } = await server.services.authToken.fnValidateJwtIdentity(token);
|
const { user, tokenVersionId, orgId, rootOrgId, parentOrgId } =
|
||||||
|
await server.services.authToken.fnValidateJwtIdentity(token, subOrganizationSelector);
|
||||||
requestContext.set("orgId", orgId);
|
requestContext.set("orgId", orgId);
|
||||||
|
|
||||||
req.auth = {
|
req.auth = {
|
||||||
authMode: AuthMode.JWT,
|
authMode: AuthMode.JWT,
|
||||||
user,
|
user,
|
||||||
userId: user.id,
|
userId: user.id,
|
||||||
tokenVersionId,
|
tokenVersionId,
|
||||||
actor,
|
actor,
|
||||||
orgId: orgId as string,
|
orgId,
|
||||||
|
rootOrgId,
|
||||||
|
parentOrgId,
|
||||||
authMethod: token.authMethod,
|
authMethod: token.authMethod,
|
||||||
isMfaVerified: token.isMfaVerified,
|
isMfaVerified: token.isMfaVerified,
|
||||||
token
|
token
|
||||||
@@ -154,13 +174,19 @@ export const injectIdentity = fp(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
case AuthMode.IDENTITY_ACCESS_TOKEN: {
|
||||||
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(token, req.realIp);
|
const identity = await server.services.identityAccessToken.fnValidateIdentityAccessToken(
|
||||||
|
token,
|
||||||
|
subOrganizationSelector,
|
||||||
|
req.realIp
|
||||||
|
);
|
||||||
const serverCfg = await getServerCfg();
|
const serverCfg = await getServerCfg();
|
||||||
requestContext.set("orgId", identity.orgId);
|
requestContext.set("orgId", identity.orgId);
|
||||||
req.auth = {
|
req.auth = {
|
||||||
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
||||||
actor,
|
actor,
|
||||||
orgId: identity.orgId,
|
orgId: identity.orgId,
|
||||||
|
rootOrgId: identity.rootOrgId,
|
||||||
|
parentOrgId: identity.parentOrgId,
|
||||||
identityId: identity.identityId,
|
identityId: identity.identityId,
|
||||||
identityName: identity.name,
|
identityName: identity.name,
|
||||||
authMethod: null,
|
authMethod: null,
|
||||||
@@ -190,8 +216,14 @@ export const injectIdentity = fp(
|
|||||||
case AuthMode.SERVICE_TOKEN: {
|
case AuthMode.SERVICE_TOKEN: {
|
||||||
const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token);
|
const serviceToken = await server.services.serviceToken.fnValidateServiceToken(token);
|
||||||
requestContext.set("orgId", serviceToken.orgId);
|
requestContext.set("orgId", serviceToken.orgId);
|
||||||
|
|
||||||
|
if (subOrganizationSelector)
|
||||||
|
throw new BadRequestError({ message: `Service token doesn't support sub organization selector` });
|
||||||
|
|
||||||
req.auth = {
|
req.auth = {
|
||||||
orgId: serviceToken.orgId,
|
orgId: serviceToken.orgId,
|
||||||
|
rootOrgId: serviceToken.rootOrgId,
|
||||||
|
parentOrgId: serviceToken.parentOrgId,
|
||||||
authMode: AuthMode.SERVICE_TOKEN as const,
|
authMode: AuthMode.SERVICE_TOKEN as const,
|
||||||
serviceToken,
|
serviceToken,
|
||||||
serviceTokenId: serviceToken.id,
|
serviceTokenId: serviceToken.id,
|
||||||
@@ -202,22 +234,27 @@ export const injectIdentity = fp(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AuthMode.API_KEY: {
|
case AuthMode.API_KEY: {
|
||||||
const user = await server.services.apiKey.fnValidateApiKey(token as string);
|
throw new BadRequestError({
|
||||||
req.auth = {
|
message: "API key authentication is not supported anymore. Please switch to identity authentication."
|
||||||
authMode: AuthMode.API_KEY as const,
|
});
|
||||||
userId: user.id,
|
|
||||||
actor,
|
|
||||||
user,
|
|
||||||
orgId: "API_KEY", // We set the orgId to an arbitrary value, since we can't link an API key to a specific org. We have to deprecate API keys soon!
|
|
||||||
authMethod: null,
|
|
||||||
token: token as string
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case AuthMode.SCIM_TOKEN: {
|
case AuthMode.SCIM_TOKEN: {
|
||||||
const { orgId, scimTokenId } = await server.services.scim.fnValidateScimToken(token);
|
const { orgId, scimTokenId } = await server.services.scim.fnValidateScimToken(token);
|
||||||
requestContext.set("orgId", orgId);
|
requestContext.set("orgId", orgId);
|
||||||
req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId, authMethod: null };
|
|
||||||
|
if (subOrganizationSelector)
|
||||||
|
throw new BadRequestError({ message: `SCIM token doesn't support sub organization selector` });
|
||||||
|
|
||||||
|
req.auth = {
|
||||||
|
authMode: AuthMode.SCIM_TOKEN,
|
||||||
|
actor,
|
||||||
|
scimTokenId,
|
||||||
|
orgId,
|
||||||
|
authMethod: null,
|
||||||
|
// scim cannot be done for sub organization
|
||||||
|
rootOrgId: orgId,
|
||||||
|
parentOrgId: orgId
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ export const injectPermission = fp(async (server) => {
|
|||||||
type: ActorType.USER,
|
type: ActorType.USER,
|
||||||
id: req.auth.userId,
|
id: req.auth.userId,
|
||||||
orgId: req.auth.orgId, // if the req.auth.authMode is AuthMode.API_KEY, the orgId will be "API_KEY"
|
orgId: req.auth.orgId, // if the req.auth.authMode is AuthMode.API_KEY, the orgId will be "API_KEY"
|
||||||
authMethod: req.auth.authMethod // if the req.auth.authMode is AuthMode.API_KEY, the authMethod will be null
|
authMethod: req.auth.authMethod, // if the req.auth.authMode is AuthMode.API_KEY, the authMethod will be null
|
||||||
|
rootOrgId: req.auth.rootOrgId,
|
||||||
|
parentOrgId: req.auth.parentOrgId
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -25,7 +27,9 @@ export const injectPermission = fp(async (server) => {
|
|||||||
type: ActorType.IDENTITY,
|
type: ActorType.IDENTITY,
|
||||||
id: req.auth.identityId,
|
id: req.auth.identityId,
|
||||||
orgId: req.auth.orgId,
|
orgId: req.auth.orgId,
|
||||||
authMethod: null
|
authMethod: null,
|
||||||
|
rootOrgId: req.auth.rootOrgId,
|
||||||
|
parentOrgId: req.auth.parentOrgId
|
||||||
};
|
};
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
@@ -36,6 +40,8 @@ export const injectPermission = fp(async (server) => {
|
|||||||
type: ActorType.SERVICE,
|
type: ActorType.SERVICE,
|
||||||
id: req.auth.serviceTokenId,
|
id: req.auth.serviceTokenId,
|
||||||
orgId: req.auth.orgId,
|
orgId: req.auth.orgId,
|
||||||
|
rootOrgId: req.auth.rootOrgId,
|
||||||
|
parentOrgId: req.auth.parentOrgId,
|
||||||
authMethod: null
|
authMethod: null
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,6 +53,8 @@ export const injectPermission = fp(async (server) => {
|
|||||||
type: ActorType.SCIM_CLIENT,
|
type: ActorType.SCIM_CLIENT,
|
||||||
id: req.auth.scimTokenId,
|
id: req.auth.scimTokenId,
|
||||||
orgId: req.auth.orgId,
|
orgId: req.auth.orgId,
|
||||||
|
rootOrgId: req.auth.rootOrgId,
|
||||||
|
parentOrgId: req.auth.parentOrgId,
|
||||||
authMethod: null
|
authMethod: null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -131,6 +131,7 @@ import { sshHostLoginUserDALFactory } from "@app/ee/services/ssh-host/ssh-login-
|
|||||||
import { sshHostGroupDALFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-dal";
|
import { sshHostGroupDALFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-dal";
|
||||||
import { sshHostGroupMembershipDALFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-membership-dal";
|
import { sshHostGroupMembershipDALFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-membership-dal";
|
||||||
import { sshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-service";
|
import { sshHostGroupServiceFactory } from "@app/ee/services/ssh-host-group/ssh-host-group-service";
|
||||||
|
import { subOrgServiceFactory } from "@app/ee/services/sub-org/sub-org-service";
|
||||||
import { trustedIpDALFactory } from "@app/ee/services/trusted-ip/trusted-ip-dal";
|
import { trustedIpDALFactory } from "@app/ee/services/trusted-ip/trusted-ip-dal";
|
||||||
import { trustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-service";
|
import { trustedIpServiceFactory } from "@app/ee/services/trusted-ip/trusted-ip-service";
|
||||||
import { keyValueStoreDALFactory } from "@app/keystore/key-value-store-dal";
|
import { keyValueStoreDALFactory } from "@app/keystore/key-value-store-dal";
|
||||||
@@ -568,11 +569,10 @@ export const registerRoutes = async (
|
|||||||
orgDAL,
|
orgDAL,
|
||||||
licenseDAL,
|
licenseDAL,
|
||||||
keyStore,
|
keyStore,
|
||||||
identityOrgMembershipDAL,
|
|
||||||
projectDAL
|
projectDAL
|
||||||
});
|
});
|
||||||
|
|
||||||
const tokenService = tokenServiceFactory({ tokenDAL: authTokenDAL, userDAL, membershipUserDAL });
|
const tokenService = tokenServiceFactory({ tokenDAL: authTokenDAL, userDAL, membershipUserDAL, orgDAL });
|
||||||
|
|
||||||
const membershipUserService = membershipUserServiceFactory({
|
const membershipUserService = membershipUserServiceFactory({
|
||||||
licenseService,
|
licenseService,
|
||||||
@@ -592,6 +592,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const membershipIdentityService = membershipIdentityServiceFactory({
|
const membershipIdentityService = membershipIdentityServiceFactory({
|
||||||
|
identityDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
membershipRoleDAL,
|
membershipRoleDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
@@ -912,6 +913,15 @@ export const registerRoutes = async (
|
|||||||
userGroupMembershipDAL,
|
userGroupMembershipDAL,
|
||||||
additionalPrivilegeDAL
|
additionalPrivilegeDAL
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const subOrgService = subOrgServiceFactory({
|
||||||
|
licenseService,
|
||||||
|
membershipDAL,
|
||||||
|
membershipRoleDAL,
|
||||||
|
orgDAL,
|
||||||
|
permissionService
|
||||||
|
});
|
||||||
|
|
||||||
const signupService = authSignupServiceFactory({
|
const signupService = authSignupServiceFactory({
|
||||||
tokenService,
|
tokenService,
|
||||||
smtpService,
|
smtpService,
|
||||||
@@ -1594,10 +1604,12 @@ export const registerRoutes = async (
|
|||||||
permissionService,
|
permissionService,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
accessTokenQueue,
|
accessTokenQueue,
|
||||||
smtpService
|
smtpService,
|
||||||
|
orgDAL
|
||||||
});
|
});
|
||||||
|
|
||||||
const identityService = identityServiceFactory({
|
const identityService = identityServiceFactory({
|
||||||
|
additionalPrivilegeDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
identityDAL,
|
identityDAL,
|
||||||
identityOrgMembershipDAL,
|
identityOrgMembershipDAL,
|
||||||
@@ -1628,10 +1640,12 @@ export const registerRoutes = async (
|
|||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
accessTokenQueue,
|
accessTokenQueue,
|
||||||
identityDAL,
|
identityDAL,
|
||||||
membershipIdentityDAL
|
membershipIdentityDAL,
|
||||||
|
orgDAL
|
||||||
});
|
});
|
||||||
|
|
||||||
const identityTokenAuthService = identityTokenAuthServiceFactory({
|
const identityTokenAuthService = identityTokenAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityTokenAuthDAL,
|
identityTokenAuthDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
@@ -1641,6 +1655,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const identityUaService = identityUaServiceFactory({
|
const identityUaService = identityUaServiceFactory({
|
||||||
|
identityDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityUaClientSecretDAL,
|
identityUaClientSecretDAL,
|
||||||
@@ -1652,6 +1667,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const identityKubernetesAuthService = identityKubernetesAuthServiceFactory({
|
const identityKubernetesAuthService = identityKubernetesAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityKubernetesAuthDAL,
|
identityKubernetesAuthDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
@@ -1665,6 +1681,7 @@ export const registerRoutes = async (
|
|||||||
membershipIdentityDAL
|
membershipIdentityDAL
|
||||||
});
|
});
|
||||||
const identityGcpAuthService = identityGcpAuthServiceFactory({
|
const identityGcpAuthService = identityGcpAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityGcpAuthDAL,
|
identityGcpAuthDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
@@ -1674,6 +1691,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const identityAliCloudAuthService = identityAliCloudAuthServiceFactory({
|
const identityAliCloudAuthService = identityAliCloudAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
identityAliCloudAuthDAL,
|
identityAliCloudAuthDAL,
|
||||||
@@ -1683,6 +1701,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const identityTlsCertAuthService = identityTlsCertAuthServiceFactory({
|
const identityTlsCertAuthService = identityTlsCertAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityTlsCertAuthDAL,
|
identityTlsCertAuthDAL,
|
||||||
licenseService,
|
licenseService,
|
||||||
@@ -1692,6 +1711,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const identityAwsAuthService = identityAwsAuthServiceFactory({
|
const identityAwsAuthService = identityAwsAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
identityAwsAuthDAL,
|
identityAwsAuthDAL,
|
||||||
@@ -1701,6 +1721,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const identityAzureAuthService = identityAzureAuthServiceFactory({
|
const identityAzureAuthService = identityAzureAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityAzureAuthDAL,
|
identityAzureAuthDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
@@ -1710,6 +1731,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const identityOciAuthService = identityOciAuthServiceFactory({
|
const identityOciAuthService = identityOciAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
identityOciAuthDAL,
|
identityOciAuthDAL,
|
||||||
@@ -1733,6 +1755,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const identityOidcAuthService = identityOidcAuthServiceFactory({
|
const identityOidcAuthService = identityOidcAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityOidcAuthDAL,
|
identityOidcAuthDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
@@ -1743,6 +1766,7 @@ export const registerRoutes = async (
|
|||||||
});
|
});
|
||||||
|
|
||||||
const identityJwtAuthService = identityJwtAuthServiceFactory({
|
const identityJwtAuthService = identityJwtAuthServiceFactory({
|
||||||
|
identityDAL,
|
||||||
identityJwtAuthDAL,
|
identityJwtAuthDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
@@ -2296,6 +2320,7 @@ export const registerRoutes = async (
|
|||||||
groupProject: groupProjectService,
|
groupProject: groupProjectService,
|
||||||
permission: permissionService,
|
permission: permissionService,
|
||||||
org: orgService,
|
org: orgService,
|
||||||
|
subOrganization: subOrgService,
|
||||||
oidc: oidcService,
|
oidc: oidcService,
|
||||||
apiKey: apiKeyService,
|
apiKey: apiKeyService,
|
||||||
authToken: tokenService,
|
authToken: tokenService,
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ export const registerAuthRoutes = async (server: FastifyZodProvider) => {
|
|||||||
decodedToken.userId,
|
decodedToken.userId,
|
||||||
decodedToken.organizationId,
|
decodedToken.organizationId,
|
||||||
decodedToken.authMethod,
|
decodedToken.authMethod,
|
||||||
|
decodedToken.organizationId,
|
||||||
decodedToken.organizationId
|
decodedToken.organizationId
|
||||||
);
|
);
|
||||||
if (org && org.userTokenExpiration) {
|
if (org && org.userTokenExpiration) {
|
||||||
|
|||||||
@@ -73,12 +73,12 @@ export const registerIdentityAliCloudAuthRouter = async (server: FastifyZodProvi
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityAliCloudAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityAliCloudAuth, accessToken, identityAccessToken, identity } =
|
||||||
await server.services.identityAliCloudAuth.login(req.body);
|
await server.services.identityAliCloudAuth.login(req.body);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_ALICLOUD_AUTH,
|
type: EventType.LOGIN_IDENTITY_ALICLOUD_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -40,12 +40,12 @@ export const registerIdentityAwsAuthRouter = async (server: FastifyZodProvider)
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityAwsAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityAwsAuth, accessToken, identityAccessToken, identity } =
|
||||||
await server.services.identityAwsAuth.login(req.body);
|
await server.services.identityAwsAuth.login(req.body);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_AWS_AUTH,
|
type: EventType.LOGIN_IDENTITY_AWS_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ export const registerIdentityAzureAuthRouter = async (server: FastifyZodProvider
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityAzureAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityAzureAuth, accessToken, identityAccessToken, identity } =
|
||||||
await server.services.identityAzureAuth.login(req.body);
|
await server.services.identityAzureAuth.login(req.body);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_AZURE_AUTH,
|
type: EventType.LOGIN_IDENTITY_AZURE_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ export const registerIdentityGcpAuthRouter = async (server: FastifyZodProvider)
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityGcpAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityGcpAuth, accessToken, identityAccessToken, identity } =
|
||||||
await server.services.identityGcpAuth.login(req.body);
|
await server.services.identityGcpAuth.login(req.body);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_GCP_AUTH,
|
type: EventType.LOGIN_IDENTITY_GCP_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider)
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityJwtAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityJwtAuth, accessToken, identityAccessToken, identity } =
|
||||||
await server.services.identityJwtAuth.login({
|
await server.services.identityJwtAuth.login({
|
||||||
identityId: req.body.identityId,
|
identityId: req.body.identityId,
|
||||||
jwt: req.body.jwt
|
jwt: req.body.jwt
|
||||||
@@ -119,7 +119,7 @@ export const registerIdentityJwtAuthRouter = async (server: FastifyZodProvider)
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_JWT_AUTH,
|
type: EventType.LOGIN_IDENTITY_JWT_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityKubernetesAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityKubernetesAuth, accessToken, identityAccessToken, identity } =
|
||||||
await server.services.identityKubernetesAuth.login({
|
await server.services.identityKubernetesAuth.login({
|
||||||
identityId: req.body.identityId,
|
identityId: req.body.identityId,
|
||||||
jwt: req.body.jwt
|
jwt: req.body.jwt
|
||||||
@@ -64,7 +64,7 @@ export const registerIdentityKubernetesRouter = async (server: FastifyZodProvide
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_KUBERNETES_AUTH,
|
type: EventType.LOGIN_IDENTITY_KUBERNETES_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -162,13 +162,13 @@ export const registerIdentityLdapAuthRouter = async (server: FastifyZodProvider)
|
|||||||
|
|
||||||
const { identityId, user } = req.passportMachineIdentity;
|
const { identityId, user } = req.passportMachineIdentity;
|
||||||
|
|
||||||
const { accessToken, identityLdapAuth, identityMembershipOrg } = await server.services.identityLdapAuth.login({
|
const { accessToken, identityLdapAuth, identity } = await server.services.identityLdapAuth.login({
|
||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_LDAP_AUTH,
|
type: EventType.LOGIN_IDENTITY_LDAP_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ export const registerIdentityOciAuthRouter = async (server: FastifyZodProvider)
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityOciAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityOciAuth, accessToken, identityAccessToken, identity } =
|
||||||
await server.services.identityOciAuth.login(req.body);
|
await server.services.identityOciAuth.login(req.body);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_OCI_AUTH,
|
type: EventType.LOGIN_IDENTITY_OCI_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider)
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityOidcAuth, accessToken, identityAccessToken, identityMembershipOrg, oidcTokenData } =
|
const { identityOidcAuth, accessToken, identityAccessToken, identity, oidcTokenData } =
|
||||||
await server.services.identityOidcAuth.login({
|
await server.services.identityOidcAuth.login({
|
||||||
identityId: req.body.identityId,
|
identityId: req.body.identityId,
|
||||||
jwt: req.body.jwt
|
jwt: req.body.jwt
|
||||||
@@ -67,7 +67,7 @@ export const registerIdentityOidcAuthRouter = async (server: FastifyZodProvider)
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_OIDC_AUTH,
|
type: EventType.LOGIN_IDENTITY_OIDC_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -0,0 +1,137 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
import { AccessScope, TemporaryPermissionMode } from "@app/db/schemas";
|
||||||
|
import { ApiDocsTags, PROJECT_IDENTITIES } from "@app/lib/api-docs";
|
||||||
|
import { ms } from "@app/lib/ms";
|
||||||
|
import { writeLimit } from "@app/server/config/rateLimiter";
|
||||||
|
import { verifyAuth } from "@app/server/plugins/auth/verify-auth";
|
||||||
|
import { AuthMode } from "@app/services/auth/auth-type";
|
||||||
|
|
||||||
|
const sanitizedOrgIdentityMembershipSchema = z.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
orgId: z.string(),
|
||||||
|
identityId: z.string().uuid(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date()
|
||||||
|
});
|
||||||
|
|
||||||
|
export const registerOrgIdentityMembershipRouter = async (server: FastifyZodProvider) => {
|
||||||
|
server.route({
|
||||||
|
method: "POST",
|
||||||
|
url: "/identity-memberships/:identityId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
hide: true,
|
||||||
|
// this is hidden so not updating tags
|
||||||
|
tags: [ApiDocsTags.ProjectIdentities],
|
||||||
|
description: "Create org identity membership",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: z.object({
|
||||||
|
identityId: z.string().trim()
|
||||||
|
}),
|
||||||
|
body: z.object({
|
||||||
|
roles: z
|
||||||
|
.array(
|
||||||
|
z.union([
|
||||||
|
z.object({
|
||||||
|
role: z.string().describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||||
|
isTemporary: z
|
||||||
|
.literal(false)
|
||||||
|
.default(false)
|
||||||
|
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role)
|
||||||
|
}),
|
||||||
|
z.object({
|
||||||
|
role: z.string().describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||||
|
isTemporary: z.literal(true).describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||||
|
temporaryMode: z
|
||||||
|
.nativeEnum(TemporaryPermissionMode)
|
||||||
|
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||||
|
temporaryRange: z
|
||||||
|
.string()
|
||||||
|
.refine((val) => ms(val) > 0, "Temporary range must be a positive number")
|
||||||
|
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role),
|
||||||
|
temporaryAccessStartTime: z
|
||||||
|
.string()
|
||||||
|
.datetime()
|
||||||
|
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.role)
|
||||||
|
})
|
||||||
|
])
|
||||||
|
)
|
||||||
|
.describe(PROJECT_IDENTITIES.CREATE_IDENTITY_MEMBERSHIP.roles.description)
|
||||||
|
.max(1)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
identityMembership: sanitizedOrgIdentityMembershipSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const { membership } = await server.services.membershipIdentity.createMembership({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Organization,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
identityId: req.params.identityId,
|
||||||
|
roles: req.body.roles
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
identityMembership: { ...membership, identityId: req.params.identityId, orgId: req.permission.orgId }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "DELETE",
|
||||||
|
url: "/identity-memberships/:identityId",
|
||||||
|
config: {
|
||||||
|
rateLimit: writeLimit
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
schema: {
|
||||||
|
hide: true,
|
||||||
|
tags: [ApiDocsTags.ProjectIdentities],
|
||||||
|
description: "Delete org identity memberships",
|
||||||
|
security: [
|
||||||
|
{
|
||||||
|
bearerAuth: []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
params: z.object({
|
||||||
|
identityId: z.string().trim().describe(PROJECT_IDENTITIES.DELETE_IDENTITY_MEMBERSHIP.identityId)
|
||||||
|
}),
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
identityMembership: sanitizedOrgIdentityMembershipSchema
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
handler: async (req) => {
|
||||||
|
const { membership } = await server.services.membershipIdentity.deleteMembership({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
scope: AccessScope.Organization,
|
||||||
|
orgId: req.permission.orgId
|
||||||
|
},
|
||||||
|
selector: {
|
||||||
|
identityId: req.params.identityId
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
identityMembership: { ...membership, identityId: req.params.identityId, orgId: req.permission.orgId }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -249,7 +249,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
permissions: true,
|
permissions: true,
|
||||||
description: true
|
description: true
|
||||||
}).optional(),
|
}).optional(),
|
||||||
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true }).extend({
|
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true, orgId: true }).extend({
|
||||||
authMethods: z.array(z.string()),
|
authMethods: z.array(z.string()),
|
||||||
activeLockoutAuthMethods: z.array(z.string())
|
activeLockoutAuthMethods: z.array(z.string())
|
||||||
})
|
})
|
||||||
@@ -393,7 +393,7 @@ export const registerIdentityRouter = async (server: FastifyZodProvider) => {
|
|||||||
permissions: true,
|
permissions: true,
|
||||||
description: true
|
description: true
|
||||||
}).optional(),
|
}).optional(),
|
||||||
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true }).extend({
|
identity: IdentitiesSchema.pick({ name: true, id: true, hasDeleteProtection: true, orgId: true }).extend({
|
||||||
authMethods: z.array(z.string())
|
authMethods: z.array(z.string())
|
||||||
})
|
})
|
||||||
}).array(),
|
}).array(),
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export const registerIdentityTlsCertAuthRouter = async (server: FastifyZodProvid
|
|||||||
throw new BadRequestError({ message: "Missing TLS certificate in header" });
|
throw new BadRequestError({ message: "Missing TLS certificate in header" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { identityTlsCertAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityTlsCertAuth, accessToken, identityAccessToken, identity } =
|
||||||
await server.services.identityTlsCertAuth.login({
|
await server.services.identityTlsCertAuth.login({
|
||||||
identityId: req.body.identityId,
|
identityId: req.body.identityId,
|
||||||
clientCertificate: clientCertificate as string
|
clientCertificate: clientCertificate as string
|
||||||
@@ -72,7 +72,7 @@ export const registerIdentityTlsCertAuthRouter = async (server: FastifyZodProvid
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_TLS_CERT_AUTH,
|
type: EventType.LOGIN_IDENTITY_TLS_CERT_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -319,7 +319,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handler: async (req) => {
|
handler: async (req) => {
|
||||||
const { identityTokenAuth, accessToken, identityAccessToken, identityMembershipOrg } =
|
const { identityTokenAuth, accessToken, identityAccessToken, identity } =
|
||||||
await server.services.identityTokenAuth.createTokenAuthToken({
|
await server.services.identityTokenAuth.createTokenAuthToken({
|
||||||
actor: req.permission.type,
|
actor: req.permission.type,
|
||||||
actorId: req.permission.id,
|
actorId: req.permission.id,
|
||||||
@@ -332,7 +332,7 @@ export const registerIdentityTokenAuthRouter = async (server: FastifyZodProvider
|
|||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.CREATE_TOKEN_IDENTITY_TOKEN_AUTH,
|
type: EventType.CREATE_TOKEN_IDENTITY_TOKEN_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -52,14 +52,14 @@ export const registerIdentityUaRouter = async (server: FastifyZodProvider) => {
|
|||||||
accessToken,
|
accessToken,
|
||||||
identityAccessToken,
|
identityAccessToken,
|
||||||
validClientSecretInfo,
|
validClientSecretInfo,
|
||||||
identityMembershipOrg,
|
identity,
|
||||||
accessTokenTTL,
|
accessTokenTTL,
|
||||||
accessTokenMaxTTL
|
accessTokenMaxTTL
|
||||||
} = await server.services.identityUa.login(req.body.clientId, req.body.clientSecret, req.realIp);
|
} = await server.services.identityUa.login(req.body.clientId, req.body.clientSecret, req.realIp);
|
||||||
|
|
||||||
await server.services.auditLog.createAuditLog({
|
await server.services.auditLog.createAuditLog({
|
||||||
...req.auditLogInfo,
|
...req.auditLogInfo,
|
||||||
orgId: identityMembershipOrg.scopeOrgId,
|
orgId: identity.orgId,
|
||||||
event: {
|
event: {
|
||||||
type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH,
|
type: EventType.LOGIN_IDENTITY_UNIVERSAL_AUTH,
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import { registerIdentityKubernetesRouter } from "./identity-kubernetes-auth-rou
|
|||||||
import { registerIdentityLdapAuthRouter } from "./identity-ldap-auth-router";
|
import { registerIdentityLdapAuthRouter } from "./identity-ldap-auth-router";
|
||||||
import { registerIdentityOciAuthRouter } from "./identity-oci-auth-router";
|
import { registerIdentityOciAuthRouter } from "./identity-oci-auth-router";
|
||||||
import { registerIdentityOidcAuthRouter } from "./identity-oidc-auth-router";
|
import { registerIdentityOidcAuthRouter } from "./identity-oidc-auth-router";
|
||||||
|
import { registerOrgIdentityMembershipRouter } from "./identity-org-membership-router";
|
||||||
import { registerIdentityProjectRouter } from "./identity-project-router";
|
import { registerIdentityProjectRouter } from "./identity-project-router";
|
||||||
import { registerIdentityRouter } from "./identity-router";
|
import { registerIdentityRouter } from "./identity-router";
|
||||||
import { registerIdentityTlsCertAuthRouter } from "./identity-tls-cert-auth-router";
|
import { registerIdentityTlsCertAuthRouter } from "./identity-tls-cert-auth-router";
|
||||||
@@ -90,6 +91,7 @@ export const registerV1Routes = async (server: FastifyZodProvider) => {
|
|||||||
);
|
);
|
||||||
await server.register(registerPasswordRouter, { prefix: "/password" });
|
await server.register(registerPasswordRouter, { prefix: "/password" });
|
||||||
await server.register(registerOrgRouter, { prefix: "/organization" });
|
await server.register(registerOrgRouter, { prefix: "/organization" });
|
||||||
|
await server.register(registerOrgIdentityMembershipRouter, { prefix: "/organization" });
|
||||||
await server.register(registerAdminRouter, { prefix: "/admin" });
|
await server.register(registerAdminRouter, { prefix: "/admin" });
|
||||||
await server.register(registerOrgAdminRouter, { prefix: "/organization-admin" });
|
await server.register(registerOrgAdminRouter, { prefix: "/organization-admin" });
|
||||||
await server.register(registerUserRouter, { prefix: "/user" });
|
await server.register(registerUserRouter, { prefix: "/user" });
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import RE2 from "re2";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AccessScope,
|
||||||
AuditLogsSchema,
|
AuditLogsSchema,
|
||||||
GroupsSchema,
|
GroupsSchema,
|
||||||
IncidentContactsSchema,
|
IncidentContactsSchema,
|
||||||
@@ -59,7 +60,14 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
200: z.object({
|
200: z.object({
|
||||||
organization: sanitizedOrganizationSchema
|
organization: sanitizedOrganizationSchema.extend({
|
||||||
|
subOrganization: z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string()
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -69,6 +77,7 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
req.permission.id,
|
req.permission.id,
|
||||||
req.params.organizationId,
|
req.params.organizationId,
|
||||||
req.permission.authMethod,
|
req.permission.authMethod,
|
||||||
|
req.permission.rootOrgId,
|
||||||
req.permission.orgId
|
req.permission.orgId
|
||||||
);
|
);
|
||||||
return { organization };
|
return { organization };
|
||||||
@@ -467,4 +476,68 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
return { groups };
|
return { groups };
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/users/available",
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
users: z
|
||||||
|
.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
username: z.string(),
|
||||||
|
email: z.string().nullable().optional(),
|
||||||
|
firstName: z.string().nullable().optional(),
|
||||||
|
lastName: z.string().nullable().optional()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { users } = await server.services.membershipUser.listAvailableUsers({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
scope: AccessScope.Organization
|
||||||
|
},
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { users };
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
server.route({
|
||||||
|
method: "GET",
|
||||||
|
url: "/identities/available",
|
||||||
|
schema: {
|
||||||
|
response: {
|
||||||
|
200: z.object({
|
||||||
|
identities: z
|
||||||
|
.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
name: z.string(),
|
||||||
|
hasDeleteProtection: z.boolean()
|
||||||
|
})
|
||||||
|
.array()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequest: verifyAuth([AuthMode.JWT]),
|
||||||
|
handler: async (req) => {
|
||||||
|
const { identities } = await server.services.membershipIdentity.listAvailableIdentities({
|
||||||
|
permission: req.permission,
|
||||||
|
scopeData: {
|
||||||
|
orgId: req.permission.orgId,
|
||||||
|
scope: AccessScope.Organization
|
||||||
|
},
|
||||||
|
data: {}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { identities };
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ export const registerIdentityOrgRouter = async (server: FastifyZodProvider) => {
|
|||||||
permissions: true,
|
permissions: true,
|
||||||
description: true
|
description: true
|
||||||
}).optional(),
|
}).optional(),
|
||||||
identity: IdentitiesSchema.pick({ name: true, id: true }).extend({
|
identity: IdentitiesSchema.pick({ name: true, id: true, orgId: true }).extend({
|
||||||
authMethods: z.array(z.string())
|
authMethods: z.array(z.string())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError, subject } from "@casl/ability";
|
import { ForbiddenError, subject } from "@casl/ability";
|
||||||
|
|
||||||
import { ActionProjectType, TAppConnections } from "@app/db/schemas";
|
import { ActionProjectType, OrganizationActionScope, TAppConnections } from "@app/db/schemas";
|
||||||
import { ValidateOCIConnectionCredentialsSchema } from "@app/ee/services/app-connections/oci";
|
import { ValidateOCIConnectionCredentialsSchema } from "@app/ee/services/app-connections/oci";
|
||||||
import { ociConnectionService } from "@app/ee/services/app-connections/oci/oci-connection-service";
|
import { ociConnectionService } from "@app/ee/services/app-connections/oci/oci-connection-service";
|
||||||
import { ValidateOracleDBConnectionCredentialsSchema } from "@app/ee/services/app-connections/oracledb";
|
import { ValidateOracleDBConnectionCredentialsSchema } from "@app/ee/services/app-connections/oracledb";
|
||||||
@@ -215,13 +215,14 @@ export const appConnectionServiceFactory = ({
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionAppConnectionActions.Read,
|
OrgPermissionAppConnectionActions.Read,
|
||||||
@@ -268,13 +269,14 @@ export const appConnectionServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.AppConnections, { connectionId })
|
subject(ProjectPermissionSub.AppConnections, { connectionId })
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
appConnection.orgId,
|
orgId: appConnection.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionAppConnectionActions.Read,
|
OrgPermissionAppConnectionActions.Read,
|
||||||
@@ -318,13 +320,14 @@ export const appConnectionServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.AppConnections, { connectionId: appConnection.id })
|
subject(ProjectPermissionSub.AppConnections, { connectionId: appConnection.id })
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
appConnection.orgId,
|
orgId: appConnection.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionAppConnectionActions.Read,
|
OrgPermissionAppConnectionActions.Read,
|
||||||
@@ -342,13 +345,14 @@ export const appConnectionServiceFactory = ({
|
|||||||
{ method, app, credentials, gatewayId, projectId, ...params }: TCreateAppConnectionDTO,
|
{ method, app, credentials, gatewayId, projectId, ...params }: TCreateAppConnectionDTO,
|
||||||
actor: OrgServiceActor
|
actor: OrgServiceActor
|
||||||
) => {
|
) => {
|
||||||
const { permission: orgPermission } = await permissionService.getOrgPermission(
|
const { permission: orgPermission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
const project = await projectDAL.findProjectById(projectId);
|
const project = await projectDAL.findProjectById(projectId);
|
||||||
@@ -477,13 +481,14 @@ export const appConnectionServiceFactory = ({
|
|||||||
"Failed to update app connection due to plan restriction. Upgrade plan to access enterprise app connections."
|
"Failed to update app connection due to plan restriction. Upgrade plan to access enterprise app connections."
|
||||||
);
|
);
|
||||||
|
|
||||||
const { permission: orgPermission } = await permissionService.getOrgPermission(
|
const { permission: orgPermission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
appConnection.orgId,
|
orgId: appConnection.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (appConnection.projectId) {
|
if (appConnection.projectId) {
|
||||||
const { permission } = await permissionService.getProjectPermission({
|
const { permission } = await permissionService.getProjectPermission({
|
||||||
@@ -635,13 +640,14 @@ export const appConnectionServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.AppConnections, { connectionId })
|
subject(ProjectPermissionSub.AppConnections, { connectionId })
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
appConnection.orgId,
|
orgId: appConnection.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionAppConnectionActions.Delete,
|
OrgPermissionAppConnectionActions.Delete,
|
||||||
@@ -704,13 +710,14 @@ export const appConnectionServiceFactory = ({
|
|||||||
subject(ProjectPermissionSub.AppConnections, { connectionId })
|
subject(ProjectPermissionSub.AppConnections, { connectionId })
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const { permission: orgPermission } = await permissionService.getOrgPermission(
|
const { permission: orgPermission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
appConnection.orgId,
|
orgId: appConnection.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(orgPermission).throwUnlessCan(
|
ForbiddenError.from(orgPermission).throwUnlessCan(
|
||||||
OrgPermissionAppConnectionActions.Connect,
|
OrgPermissionAppConnectionActions.Connect,
|
||||||
@@ -747,13 +754,14 @@ export const appConnectionServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const listAvailableAppConnectionsForUser = async (app: AppConnection, actor: OrgServiceActor, projectId?: string) => {
|
const listAvailableAppConnectionsForUser = async (app: AppConnection, actor: OrgServiceActor, projectId?: string) => {
|
||||||
const { permission: orgPermission } = await permissionService.getOrgPermission(
|
const { permission: orgPermission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
let availableProjectConnections: TAppConnections[] = [];
|
let availableProjectConnections: TAppConnections[] = [];
|
||||||
|
|
||||||
@@ -805,13 +813,14 @@ export const appConnectionServiceFactory = ({
|
|||||||
|
|
||||||
if (!appConnection) throw new NotFoundError({ message: `Could not find App Connection with ID ${connectionId}` });
|
if (!appConnection) throw new NotFoundError({ message: `Could not find App Connection with ID ${connectionId}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
appConnection.orgId,
|
orgId: appConnection.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionAppConnectionActions.Read,
|
OrgPermissionAppConnectionActions.Read,
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ import { Knex } from "knex";
|
|||||||
import { AccessScope, TAuthTokens, TAuthTokenSessions } from "@app/db/schemas";
|
import { AccessScope, TAuthTokens, TAuthTokenSessions } from "@app/db/schemas";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
|
import { BadRequestError, ForbiddenRequestError, NotFoundError, UnauthorizedError } from "@app/lib/errors";
|
||||||
|
|
||||||
import { AuthModeJwtTokenPayload, AuthModeRefreshJwtTokenPayload, AuthTokenType } from "../auth/auth-type";
|
import { AuthModeJwtTokenPayload, AuthModeRefreshJwtTokenPayload, AuthTokenType } from "../auth/auth-type";
|
||||||
import { TMembershipUserDALFactory } from "../membership-user/membership-user-dal";
|
import { TMembershipUserDALFactory } from "../membership-user/membership-user-dal";
|
||||||
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
import { TUserDALFactory } from "../user/user-dal";
|
import { TUserDALFactory } from "../user/user-dal";
|
||||||
import { TTokenDALFactory } from "./auth-token-dal";
|
import { TTokenDALFactory } from "./auth-token-dal";
|
||||||
import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenForUserDTO } from "./auth-token-types";
|
import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenForUserDTO } from "./auth-token-types";
|
||||||
@@ -14,6 +15,7 @@ import { TCreateTokenForUserDTO, TIssueAuthTokenDTO, TokenType, TValidateTokenFo
|
|||||||
type TAuthTokenServiceFactoryDep = {
|
type TAuthTokenServiceFactoryDep = {
|
||||||
tokenDAL: TTokenDALFactory;
|
tokenDAL: TTokenDALFactory;
|
||||||
userDAL: Pick<TUserDALFactory, "findById" | "transaction">;
|
userDAL: Pick<TUserDALFactory, "findById" | "transaction">;
|
||||||
|
orgDAL: Pick<TOrgDALFactory, "findOne">;
|
||||||
membershipUserDAL: Pick<TMembershipUserDALFactory, "findOne">;
|
membershipUserDAL: Pick<TMembershipUserDALFactory, "findOne">;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,7 +82,7 @@ export const getTokenConfig = (tokenType: TokenType) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tokenServiceFactory = ({ tokenDAL, userDAL, membershipUserDAL }: TAuthTokenServiceFactoryDep) => {
|
export const tokenServiceFactory = ({ tokenDAL, userDAL, membershipUserDAL, orgDAL }: TAuthTokenServiceFactoryDep) => {
|
||||||
const createTokenForUser = async ({ type, userId, orgId, aliasId, payload }: TCreateTokenForUserDTO) => {
|
const createTokenForUser = async ({ type, userId, orgId, aliasId, payload }: TCreateTokenForUserDTO) => {
|
||||||
const { token, ...tkCfg } = getTokenConfig(type);
|
const { token, ...tkCfg } = getTokenConfig(type);
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
@@ -194,7 +196,7 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, membershipUserDAL }: TA
|
|||||||
};
|
};
|
||||||
|
|
||||||
// to parse jwt identity in inject identity plugin
|
// to parse jwt identity in inject identity plugin
|
||||||
const fnValidateJwtIdentity = async (token: AuthModeJwtTokenPayload) => {
|
const fnValidateJwtIdentity = async (token: AuthModeJwtTokenPayload, subOrganizationSelector?: string) => {
|
||||||
const session = await tokenDAL.findOneTokenSession({
|
const session = await tokenDAL.findOneTokenSession({
|
||||||
id: token.tokenVersionId,
|
id: token.tokenVersionId,
|
||||||
userId: token.userId
|
userId: token.userId
|
||||||
@@ -207,7 +209,35 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, membershipUserDAL }: TA
|
|||||||
const user = await userDAL.findById(session.userId);
|
const user = await userDAL.findById(session.userId);
|
||||||
if (!user || !user.isAccepted) throw new NotFoundError({ message: `User with ID '${session.userId}' not found` });
|
if (!user || !user.isAccepted) throw new NotFoundError({ message: `User with ID '${session.userId}' not found` });
|
||||||
|
|
||||||
|
let orgId = "";
|
||||||
|
let rootOrgId = "";
|
||||||
|
let parentOrgId = "";
|
||||||
if (token.organizationId) {
|
if (token.organizationId) {
|
||||||
|
if (subOrganizationSelector) {
|
||||||
|
const subOrganization = await orgDAL.findOne({
|
||||||
|
rootOrgId: token.organizationId,
|
||||||
|
slug: subOrganizationSelector
|
||||||
|
});
|
||||||
|
if (!subOrganization)
|
||||||
|
throw new BadRequestError({ message: `Sub organization ${subOrganizationSelector} not found` });
|
||||||
|
|
||||||
|
const orgMembership = await membershipUserDAL.findOne({
|
||||||
|
actorUserId: user.id,
|
||||||
|
scopeOrgId: subOrganization.id,
|
||||||
|
scope: AccessScope.Organization
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!orgMembership) {
|
||||||
|
throw new ForbiddenRequestError({ message: "User not member of organization" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!orgMembership.isActive) {
|
||||||
|
throw new ForbiddenRequestError({ message: "User organization membership is inactive" });
|
||||||
|
}
|
||||||
|
orgId = subOrganization.id;
|
||||||
|
rootOrgId = token.organizationId;
|
||||||
|
parentOrgId = subOrganization.parentOrgId as string;
|
||||||
|
} else {
|
||||||
const orgMembership = await membershipUserDAL.findOne({
|
const orgMembership = await membershipUserDAL.findOne({
|
||||||
actorUserId: user.id,
|
actorUserId: user.id,
|
||||||
scopeOrgId: token.organizationId,
|
scopeOrgId: token.organizationId,
|
||||||
@@ -217,12 +247,18 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, membershipUserDAL }: TA
|
|||||||
if (!orgMembership) {
|
if (!orgMembership) {
|
||||||
throw new ForbiddenRequestError({ message: "User not member of organization" });
|
throw new ForbiddenRequestError({ message: "User not member of organization" });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!orgMembership.isActive) {
|
if (!orgMembership.isActive) {
|
||||||
throw new ForbiddenRequestError({ message: "User organization membership is inactive" });
|
throw new ForbiddenRequestError({ message: "User organization membership is inactive" });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
orgId = token.organizationId;
|
||||||
|
rootOrgId = token.organizationId;
|
||||||
|
parentOrgId = token.organizationId;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { user, tokenVersionId: token.tokenVersionId, orgId: token.organizationId };
|
return { user, tokenVersionId: token.tokenVersionId, orgId, rootOrgId, parentOrgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -258,7 +258,13 @@ export const authSignupServiceFactory = ({
|
|||||||
let refreshTokenExpiresIn: string | number = appCfg.JWT_REFRESH_LIFETIME;
|
let refreshTokenExpiresIn: string | number = appCfg.JWT_REFRESH_LIFETIME;
|
||||||
|
|
||||||
if (organizationId) {
|
if (organizationId) {
|
||||||
const org = await orgService.findOrganizationById(user.id, organizationId, authMethod, organizationId);
|
const org = await orgService.findOrganizationById(
|
||||||
|
user.id,
|
||||||
|
organizationId,
|
||||||
|
authMethod,
|
||||||
|
organizationId,
|
||||||
|
organizationId
|
||||||
|
);
|
||||||
if (org && org.userTokenExpiration) {
|
if (org && org.userTokenExpiration) {
|
||||||
tokenSessionExpiresIn = getMinExpiresIn(appCfg.JWT_AUTH_LIFETIME, org.userTokenExpiration);
|
tokenSessionExpiresIn = getMinExpiresIn(appCfg.JWT_AUTH_LIFETIME, org.userTokenExpiration);
|
||||||
refreshTokenExpiresIn = org.userTokenExpiration;
|
refreshTokenExpiresIn = org.userTokenExpiration;
|
||||||
|
|||||||
+17
-14
@@ -1,5 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
|
import { OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
@@ -26,13 +27,14 @@ export const externalGroupOrgRoleMappingServiceFactory = ({
|
|||||||
roleDAL
|
roleDAL
|
||||||
}: TExternalGroupOrgRoleMappingServiceFactoryDep) => {
|
}: TExternalGroupOrgRoleMappingServiceFactoryDep) => {
|
||||||
const listExternalGroupOrgRoleMappings = async (actor: OrgServiceActor) => {
|
const listExternalGroupOrgRoleMappings = async (actor: OrgServiceActor) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: will need to change if we add support for ldap, oidc, etc.
|
// TODO: will need to change if we add support for ldap, oidc, etc.
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Scim);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Scim);
|
||||||
@@ -48,13 +50,14 @@ export const externalGroupOrgRoleMappingServiceFactory = ({
|
|||||||
dto: TSyncExternalGroupOrgMembershipRoleMappingsDTO,
|
dto: TSyncExternalGroupOrgMembershipRoleMappingsDTO,
|
||||||
actor: OrgServiceActor
|
actor: OrgServiceActor
|
||||||
) => {
|
) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actor: actor.type,
|
||||||
actor.id,
|
actorId: actor.id,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorAuthMethod: actor.authMethod,
|
||||||
actor.orgId
|
actorOrgId: actor.orgId,
|
||||||
);
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
|
});
|
||||||
|
|
||||||
// TODO: will need to change if we add support for ldap, oidc, etc.
|
// TODO: will need to change if we add support for ldap, oidc, etc.
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Scim);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Scim);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { OrgMembershipRole } from "@app/db/schemas";
|
import { OrganizationActionScope, OrgMembershipRole } from "@app/db/schemas";
|
||||||
import {
|
import {
|
||||||
AuditLogInfo,
|
AuditLogInfo,
|
||||||
EventType,
|
EventType,
|
||||||
@@ -89,13 +89,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "EnvKey migration is not supported when running in FIPS mode." });
|
throw new BadRequestError({ message: "EnvKey migration is not supported when running in FIPS mode." });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor,
|
|
||||||
actorId,
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId: actorOrgId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
scope: OrganizationActionScope.Any
|
||||||
);
|
});
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can import data" });
|
throw new ForbiddenRequestError({ message: "Only admins can import data" });
|
||||||
}
|
}
|
||||||
@@ -136,13 +137,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TImportVaultDataDTO) => {
|
}: TImportVaultDataDTO) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor,
|
|
||||||
actorId,
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId: actorOrgId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
scope: OrganizationActionScope.Any
|
||||||
);
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can import data" });
|
throw new ForbiddenRequestError({ message: "Only admins can import data" });
|
||||||
@@ -192,13 +194,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
provider
|
provider
|
||||||
}: THasCustomVaultMigrationDTO) => {
|
}: THasCustomVaultMigrationDTO) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor,
|
|
||||||
actorId,
|
actorId,
|
||||||
|
actor,
|
||||||
|
orgId: actorOrgId,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
scope: OrganizationActionScope.Any
|
||||||
);
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can check custom migration status" });
|
throw new ForbiddenRequestError({ message: "Only admins can check custom migration status" });
|
||||||
@@ -247,13 +250,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const createVaultExternalMigration = async ({ namespace, connectionId, actor }: TCreateVaultExternalMigrationDTO) => {
|
const createVaultExternalMigration = async ({ namespace, connectionId, actor }: TCreateVaultExternalMigrationDTO) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can configure vault external migration" });
|
throw new ForbiddenRequestError({ message: "Only admins can configure vault external migration" });
|
||||||
@@ -298,13 +302,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
connectionId,
|
connectionId,
|
||||||
actor
|
actor
|
||||||
}: TUpdateVaultExternalMigrationDTO) => {
|
}: TUpdateVaultExternalMigrationDTO) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can update vault external migration" });
|
throw new ForbiddenRequestError({ message: "Only admins can update vault external migration" });
|
||||||
@@ -332,13 +337,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getVaultExternalMigrationConfigs = async ({ actor }: { actor: OrgServiceActor }) => {
|
const getVaultExternalMigrationConfigs = async ({ actor }: { actor: OrgServiceActor }) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can view vault external migration configs" });
|
throw new ForbiddenRequestError({ message: "Only admins can view vault external migration configs" });
|
||||||
@@ -352,13 +358,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getVaultNamespaces = async ({ actor }: { actor: OrgServiceActor }) => {
|
const getVaultNamespaces = async ({ actor }: { actor: OrgServiceActor }) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can view vault namespaces" });
|
throw new ForbiddenRequestError({ message: "Only admins can view vault namespaces" });
|
||||||
@@ -380,13 +387,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getVaultPolicies = async ({ actor, namespace }: { actor: OrgServiceActor; namespace: string }) => {
|
const getVaultPolicies = async ({ actor, namespace }: { actor: OrgServiceActor; namespace: string }) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can view vault policies" });
|
throw new ForbiddenRequestError({ message: "Only admins can view vault policies" });
|
||||||
@@ -422,13 +430,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const getVaultMounts = async ({ actor, namespace }: { actor: OrgServiceActor; namespace: string }) => {
|
const getVaultMounts = async ({ actor, namespace }: { actor: OrgServiceActor; namespace: string }) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can view vault mounts" });
|
throw new ForbiddenRequestError({ message: "Only admins can view vault mounts" });
|
||||||
@@ -472,13 +481,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
namespace: string;
|
namespace: string;
|
||||||
mountPath: string;
|
mountPath: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can view vault secret paths" });
|
throw new ForbiddenRequestError({ message: "Only admins can view vault secret paths" });
|
||||||
@@ -531,13 +541,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
vaultSecretPath: string;
|
vaultSecretPath: string;
|
||||||
auditLogInfo: AuditLogInfo;
|
auditLogInfo: AuditLogInfo;
|
||||||
}) => {
|
}) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can import vault secrets" });
|
throw new ForbiddenRequestError({ message: "Only admins can import vault secrets" });
|
||||||
@@ -617,13 +628,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const deleteVaultExternalMigration = async ({ id, actor }: TDeleteVaultExternalMigrationDTO) => {
|
const deleteVaultExternalMigration = async ({ id, actor }: TDeleteVaultExternalMigrationDTO) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can delete vault external migration configs" });
|
throw new ForbiddenRequestError({ message: "Only admins can delete vault external migration configs" });
|
||||||
@@ -653,13 +665,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
namespace: string;
|
namespace: string;
|
||||||
authType?: string;
|
authType?: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can view vault auth mounts" });
|
throw new ForbiddenRequestError({ message: "Only admins can view vault auth mounts" });
|
||||||
@@ -704,13 +717,14 @@ export const externalMigrationServiceFactory = ({
|
|||||||
namespace: string;
|
namespace: string;
|
||||||
mountPath: string;
|
mountPath: string;
|
||||||
}) => {
|
}) => {
|
||||||
const { hasRole } = await permissionService.getOrgPermission(
|
const { hasRole } = await permissionService.getOrgPermission({
|
||||||
actor.type,
|
actorId: actor.id,
|
||||||
actor.id,
|
actor: actor.type,
|
||||||
actor.orgId,
|
orgId: actor.orgId,
|
||||||
actor.authMethod,
|
actorOrgId: actor.orgId,
|
||||||
actor.orgId
|
actorAuthMethod: actor.authMethod,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
if (!hasRole(OrgMembershipRole.Admin)) {
|
if (!hasRole(OrgMembershipRole.Admin)) {
|
||||||
throw new ForbiddenRequestError({ message: "Only admins can view vault Kubernetes auth roles" });
|
throw new ForbiddenRequestError({ message: "Only admins can view vault Kubernetes auth roles" });
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ export const identityAccessTokenDALFactory = (db: TDbClient) => {
|
|||||||
.join(TableName.Identity, `${TableName.Identity}.id`, `${TableName.IdentityAccessToken}.identityId`)
|
.join(TableName.Identity, `${TableName.Identity}.id`, `${TableName.IdentityAccessToken}.identityId`)
|
||||||
.select(selectAllTableCols(TableName.IdentityAccessToken))
|
.select(selectAllTableCols(TableName.IdentityAccessToken))
|
||||||
.select(db.ref("name").withSchema(TableName.Identity))
|
.select(db.ref("name").withSchema(TableName.Identity))
|
||||||
|
.select(db.ref("orgId").withSchema(TableName.Identity).as("identityScopeOrgId"))
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { TAccessTokenQueueServiceFactory } from "../access-token-queue/access-to
|
|||||||
import { AuthTokenType } from "../auth/auth-type";
|
import { AuthTokenType } from "../auth/auth-type";
|
||||||
import { TIdentityDALFactory } from "../identity/identity-dal";
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "./identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "./identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload, TRenewAccessTokenDTO } from "./identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload, TRenewAccessTokenDTO } from "./identity-access-token-types";
|
||||||
|
|
||||||
@@ -19,6 +20,7 @@ type TIdentityAccessTokenServiceFactoryDep = {
|
|||||||
"updateIdentityAccessTokenStatus" | "getIdentityTokenDetailsInCache"
|
"updateIdentityAccessTokenStatus" | "getIdentityTokenDetailsInCache"
|
||||||
>;
|
>;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne">;
|
||||||
|
orgDAL: Pick<TOrgDALFactory, "findOne">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIdentityAccessTokenServiceFactory = ReturnType<typeof identityAccessTokenServiceFactory>;
|
export type TIdentityAccessTokenServiceFactory = ReturnType<typeof identityAccessTokenServiceFactory>;
|
||||||
@@ -27,7 +29,8 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
accessTokenQueue,
|
accessTokenQueue,
|
||||||
identityDAL,
|
identityDAL,
|
||||||
membershipIdentityDAL
|
membershipIdentityDAL,
|
||||||
|
orgDAL
|
||||||
}: TIdentityAccessTokenServiceFactoryDep) => {
|
}: TIdentityAccessTokenServiceFactoryDep) => {
|
||||||
const validateAccessTokenExp = async (identityAccessToken: TIdentityAccessTokens) => {
|
const validateAccessTokenExp = async (identityAccessToken: TIdentityAccessTokens) => {
|
||||||
const {
|
const {
|
||||||
@@ -181,7 +184,11 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
return { revokedToken };
|
return { revokedToken };
|
||||||
};
|
};
|
||||||
|
|
||||||
const fnValidateIdentityAccessToken = async (token: TIdentityAccessTokenJwtPayload, ipAddress?: string) => {
|
const fnValidateIdentityAccessToken = async (
|
||||||
|
token: TIdentityAccessTokenJwtPayload,
|
||||||
|
subOrganizationSelector?: string,
|
||||||
|
ipAddress?: string
|
||||||
|
) => {
|
||||||
const identityAccessToken = await identityAccessTokenDAL.findOne({
|
const identityAccessToken = await identityAccessTokenDAL.findOne({
|
||||||
[`${TableName.IdentityAccessToken}.id` as "id"]: token.identityAccessTokenId,
|
[`${TableName.IdentityAccessToken}.id` as "id"]: token.identityAccessTokenId,
|
||||||
isAccessTokenRevoked: false
|
isAccessTokenRevoked: false
|
||||||
@@ -202,14 +209,41 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
trustedIps: trustedIps as TIp[]
|
trustedIps: trustedIps as TIp[]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
let orgId = "";
|
||||||
|
let parentOrgId = "";
|
||||||
|
const identityOrgDetails = await orgDAL.findOne({ id: identityAccessToken.identityScopeOrgId });
|
||||||
|
const rootOrgId = identityOrgDetails.rootOrgId || identityOrgDetails.id;
|
||||||
|
|
||||||
|
if (subOrganizationSelector) {
|
||||||
|
const subOrganization = await orgDAL.findOne({ rootOrgId, slug: subOrganizationSelector });
|
||||||
|
if (!subOrganization)
|
||||||
|
throw new BadRequestError({ message: `Sub organization ${subOrganizationSelector} not found` });
|
||||||
|
|
||||||
const identityOrgMembership = await membershipIdentityDAL.findOne({
|
const identityOrgMembership = await membershipIdentityDAL.findOne({
|
||||||
scope: AccessScope.Organization,
|
scope: AccessScope.Organization,
|
||||||
actorIdentityId: identityAccessToken.identityId
|
actorIdentityId: identityAccessToken.identityId,
|
||||||
|
scopeOrgId: subOrganization.id
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!identityOrgMembership) {
|
if (!identityOrgMembership) {
|
||||||
throw new BadRequestError({ message: "Identity does not belong to any organization" });
|
throw new BadRequestError({ message: "Identity does not belong to any organization" });
|
||||||
}
|
}
|
||||||
|
orgId = subOrganization.id;
|
||||||
|
parentOrgId = subOrganization.parentOrgId as string;
|
||||||
|
} else {
|
||||||
|
const identityOrgMembership = await membershipIdentityDAL.findOne({
|
||||||
|
scope: AccessScope.Organization,
|
||||||
|
actorIdentityId: identityAccessToken.identityId,
|
||||||
|
scopeOrgId: rootOrgId
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!identityOrgMembership) {
|
||||||
|
throw new BadRequestError({ message: "Identity does not belong to any organization" });
|
||||||
|
}
|
||||||
|
|
||||||
|
orgId = rootOrgId;
|
||||||
|
parentOrgId = rootOrgId;
|
||||||
|
}
|
||||||
|
|
||||||
let { accessTokenNumUses } = identityAccessToken;
|
let { accessTokenNumUses } = identityAccessToken;
|
||||||
const tokenStatusInCache = await accessTokenQueue.getIdentityTokenDetailsInCache(identityAccessToken.id);
|
const tokenStatusInCache = await accessTokenQueue.getIdentityTokenDetailsInCache(identityAccessToken.id);
|
||||||
@@ -219,7 +253,7 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
await validateAccessTokenExp({ ...identityAccessToken, accessTokenNumUses });
|
await validateAccessTokenExp({ ...identityAccessToken, accessTokenNumUses });
|
||||||
|
|
||||||
await accessTokenQueue.updateIdentityAccessTokenStatus(identityAccessToken.id, Number(accessTokenNumUses) + 1);
|
await accessTokenQueue.updateIdentityAccessTokenStatus(identityAccessToken.id, Number(accessTokenNumUses) + 1);
|
||||||
return { ...identityAccessToken, orgId: identityOrgMembership.scopeOrgId };
|
return { ...identityAccessToken, orgId, rootOrgId, parentOrgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
return { renewAccessToken, revokeAccessToken, fnValidateIdentityAccessToken };
|
return { renewAccessToken, revokeAccessToken, fnValidateIdentityAccessToken };
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -13,11 +13,18 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
|
NotFoundError,
|
||||||
|
PermissionBoundaryError,
|
||||||
|
UnauthorizedError
|
||||||
|
} from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
@@ -34,12 +41,13 @@ import {
|
|||||||
} from "./identity-alicloud-auth-types";
|
} from "./identity-alicloud-auth-types";
|
||||||
|
|
||||||
type TIdentityAliCloudAuthServiceFactoryDep = {
|
type TIdentityAliCloudAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
identityAliCloudAuthDAL: Pick<
|
identityAliCloudAuthDAL: Pick<
|
||||||
TIdentityAliCloudAuthDALFactory,
|
TIdentityAliCloudAuthDALFactory,
|
||||||
"findOne" | "transaction" | "create" | "updateById" | "delete"
|
"findOne" | "transaction" | "create" | "updateById" | "delete"
|
||||||
>;
|
>;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||||
@@ -48,6 +56,7 @@ type TIdentityAliCloudAuthServiceFactoryDep = {
|
|||||||
export type TIdentityAliCloudAuthServiceFactory = ReturnType<typeof identityAliCloudAuthServiceFactory>;
|
export type TIdentityAliCloudAuthServiceFactory = ReturnType<typeof identityAliCloudAuthServiceFactory>;
|
||||||
|
|
||||||
export const identityAliCloudAuthServiceFactory = ({
|
export const identityAliCloudAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityAliCloudAuthDAL,
|
identityAliCloudAuthDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
@@ -63,12 +72,8 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
const identity = await identityDAL.findById(identityAliCloudAuth.identityId);
|
||||||
actorIdentityId: identityAliCloudAuth.identityId,
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!identityMembershipOrg) throw new UnauthorizedError({ message: "Identity not attached to a organization" });
|
|
||||||
|
|
||||||
const requestUrl = new URL("https://sts.aliyuncs.com");
|
const requestUrl = new URL("https://sts.aliyuncs.com");
|
||||||
|
|
||||||
@@ -93,8 +98,8 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
|
|
||||||
// Generate the token
|
// Generate the token
|
||||||
const identityAccessToken = await identityAliCloudAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityAliCloudAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.ALICLOUD_AUTH,
|
lastLoginAuthMethod: IdentityAuthMethod.ALICLOUD_AUTH,
|
||||||
lastLoginTime: new Date()
|
lastLoginTime: new Date()
|
||||||
@@ -135,7 +140,7 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
identityAliCloudAuth,
|
identityAliCloudAuth,
|
||||||
accessToken,
|
accessToken,
|
||||||
identityAccessToken,
|
identityAccessToken,
|
||||||
identityMembershipOrg
|
identity
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -162,6 +167,9 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.ALICLOUD_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.ALICLOUD_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -173,13 +181,14 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -238,6 +247,9 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.ALICLOUD_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.ALICLOUD_AUTH)) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
@@ -255,13 +267,14 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -304,6 +317,9 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.ALICLOUD_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.ALICLOUD_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -313,13 +329,14 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
|
|
||||||
const alicloudIdentityAuth = await identityAliCloudAuthDAL.findOne({ identityId });
|
const alicloudIdentityAuth = await identityAliCloudAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
return { ...alicloudIdentityAuth, orgId: identityMembershipOrg.scopeOrgId };
|
return { ...alicloudIdentityAuth, orgId: identityMembershipOrg.scopeOrgId };
|
||||||
};
|
};
|
||||||
@@ -339,27 +356,32 @@ export const identityAliCloudAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.ALICLOUD_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.ALICLOUD_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have Alibaba Cloud auth"
|
message: "The identity does not have Alibaba Cloud auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
scope: OrganizationActionScope.Any,
|
||||||
identityMembershipOrg.identity.id,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.scopeOrgId,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import RE2 from "re2";
|
import RE2 from "re2";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -13,10 +13,17 @@ import {
|
|||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
|
NotFoundError,
|
||||||
|
PermissionBoundaryError,
|
||||||
|
UnauthorizedError
|
||||||
|
} from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
@@ -35,9 +42,10 @@ import {
|
|||||||
} from "./identity-aws-auth-types";
|
} from "./identity-aws-auth-types";
|
||||||
|
|
||||||
type TIdentityAwsAuthServiceFactoryDep = {
|
type TIdentityAwsAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
identityAwsAuthDAL: Pick<TIdentityAwsAuthDALFactory, "findOne" | "transaction" | "create" | "updateById" | "delete">;
|
identityAwsAuthDAL: Pick<TIdentityAwsAuthDALFactory, "findOne" | "transaction" | "create" | "updateById" | "delete">;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||||
@@ -80,6 +88,7 @@ function isValidAwsRegion(region: string | null): boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const identityAwsAuthServiceFactory = ({
|
export const identityAwsAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityAwsAuthDAL,
|
identityAwsAuthDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
@@ -93,11 +102,8 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: "AWS auth method not found for identity, did you configure AWS auth?" });
|
throw new NotFoundError({ message: "AWS auth method not found for identity, did you configure AWS auth?" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
const identity = await identityDAL.findById(identityAwsAuth.identityId);
|
||||||
actorIdentityId: identityAwsAuth.identityId,
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
if (!identityMembershipOrg) throw new UnauthorizedError({ message: "Identity not attached to a organization" });
|
|
||||||
|
|
||||||
const headers: TAwsGetCallerIdentityHeaders = JSON.parse(Buffer.from(iamRequestHeaders, "base64").toString());
|
const headers: TAwsGetCallerIdentityHeaders = JSON.parse(Buffer.from(iamRequestHeaders, "base64").toString());
|
||||||
const body: string = Buffer.from(iamRequestBody, "base64").toString();
|
const body: string = Buffer.from(iamRequestBody, "base64").toString();
|
||||||
@@ -159,8 +165,8 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const identityAccessToken = await identityAwsAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityAwsAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.AWS_AUTH,
|
lastLoginAuthMethod: IdentityAuthMethod.AWS_AUTH,
|
||||||
lastLoginTime: new Date()
|
lastLoginTime: new Date()
|
||||||
@@ -212,7 +218,7 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { accessToken, identityAwsAuth, identityAccessToken, identityMembershipOrg };
|
return { accessToken, identityAwsAuth, identityAccessToken, identity };
|
||||||
};
|
};
|
||||||
|
|
||||||
const attachAwsAuth = async ({
|
const attachAwsAuth = async ({
|
||||||
@@ -240,6 +246,9 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AWS_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AWS_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -251,13 +260,14 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -320,6 +330,9 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AWS_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AWS_AUTH)) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
@@ -336,13 +349,14 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -387,6 +401,9 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AWS_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AWS_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -396,13 +413,14 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
|
|
||||||
const awsIdentityAuth = await identityAwsAuthDAL.findOne({ identityId });
|
const awsIdentityAuth = await identityAwsAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
return { ...awsIdentityAuth, orgId: identityMembershipOrg.scopeOrgId };
|
return { ...awsIdentityAuth, orgId: identityMembershipOrg.scopeOrgId };
|
||||||
};
|
};
|
||||||
@@ -422,27 +440,32 @@ export const identityAwsAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AWS_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AWS_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have aws auth"
|
message: "The identity does not have aws auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
scope: OrganizationActionScope.Any,
|
||||||
identityMembershipOrg.identity.id,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.scopeOrgId,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -10,10 +10,17 @@ import {
|
|||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
|
NotFoundError,
|
||||||
|
PermissionBoundaryError,
|
||||||
|
UnauthorizedError
|
||||||
|
} from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
@@ -30,11 +37,12 @@ import {
|
|||||||
} from "./identity-azure-auth-types";
|
} from "./identity-azure-auth-types";
|
||||||
|
|
||||||
type TIdentityAzureAuthServiceFactoryDep = {
|
type TIdentityAzureAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityAzureAuthDAL: Pick<
|
identityAzureAuthDAL: Pick<
|
||||||
TIdentityAzureAuthDALFactory,
|
TIdentityAzureAuthDALFactory,
|
||||||
"findOne" | "transaction" | "create" | "updateById" | "delete"
|
"findOne" | "transaction" | "create" | "updateById" | "delete"
|
||||||
>;
|
>;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
@@ -44,6 +52,7 @@ type TIdentityAzureAuthServiceFactoryDep = {
|
|||||||
export type TIdentityAzureAuthServiceFactory = ReturnType<typeof identityAzureAuthServiceFactory>;
|
export type TIdentityAzureAuthServiceFactory = ReturnType<typeof identityAzureAuthServiceFactory>;
|
||||||
|
|
||||||
export const identityAzureAuthServiceFactory = ({
|
export const identityAzureAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityAzureAuthDAL,
|
identityAzureAuthDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
@@ -57,11 +66,8 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: "Azure auth method not found for identity, did you configure Azure Auth?" });
|
throw new NotFoundError({ message: "Azure auth method not found for identity, did you configure Azure Auth?" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
const identity = await identityDAL.findById(identityAzureAuth.identityId);
|
||||||
actorIdentityId: identityAzureAuth.identityId,
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
if (!identityMembershipOrg) throw new UnauthorizedError({ message: "Identity not attached to a organization" });
|
|
||||||
|
|
||||||
const azureIdentity = await validateAzureIdentity({
|
const azureIdentity = await validateAzureIdentity({
|
||||||
tenantId: identityAzureAuth.tenantId,
|
tenantId: identityAzureAuth.tenantId,
|
||||||
@@ -86,8 +92,8 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const identityAccessToken = await identityAzureAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityAzureAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.AZURE_AUTH,
|
lastLoginAuthMethod: IdentityAuthMethod.AZURE_AUTH,
|
||||||
lastLoginTime: new Date()
|
lastLoginTime: new Date()
|
||||||
@@ -125,7 +131,7 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { accessToken, identityAzureAuth, identityAccessToken, identityMembershipOrg };
|
return { accessToken, identityAzureAuth, identityAccessToken, identity };
|
||||||
};
|
};
|
||||||
|
|
||||||
const attachAzureAuth = async ({
|
const attachAzureAuth = async ({
|
||||||
@@ -153,6 +159,9 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AZURE_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AZURE_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -163,13 +172,14 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -232,6 +242,9 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AZURE_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AZURE_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Failed to update Azure Auth"
|
message: "Failed to update Azure Auth"
|
||||||
@@ -247,13 +260,14 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -301,6 +315,9 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AZURE_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AZURE_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have Azure Auth attached"
|
message: "The identity does not have Azure Auth attached"
|
||||||
@@ -309,13 +326,14 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
|
|
||||||
const identityAzureAuth = await identityAzureAuthDAL.findOne({ identityId });
|
const identityAzureAuth = await identityAzureAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
return { ...identityAzureAuth, orgId: identityMembershipOrg.scopeOrgId };
|
return { ...identityAzureAuth, orgId: identityMembershipOrg.scopeOrgId };
|
||||||
@@ -336,27 +354,32 @@ export const identityAzureAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AZURE_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.AZURE_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have azure auth"
|
message: "The identity does not have azure auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
scope: OrganizationActionScope.Any,
|
||||||
identityMembershipOrg.identity.id,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.scopeOrgId,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -10,10 +10,17 @@ import {
|
|||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
|
NotFoundError,
|
||||||
|
PermissionBoundaryError,
|
||||||
|
UnauthorizedError
|
||||||
|
} from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
@@ -31,8 +38,9 @@ import {
|
|||||||
} from "./identity-gcp-auth-types";
|
} from "./identity-gcp-auth-types";
|
||||||
|
|
||||||
type TIdentityGcpAuthServiceFactoryDep = {
|
type TIdentityGcpAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityGcpAuthDAL: Pick<TIdentityGcpAuthDALFactory, "findOne" | "transaction" | "create" | "updateById" | "delete">;
|
identityGcpAuthDAL: Pick<TIdentityGcpAuthDALFactory, "findOne" | "transaction" | "create" | "updateById" | "delete">;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
@@ -42,6 +50,7 @@ type TIdentityGcpAuthServiceFactoryDep = {
|
|||||||
export type TIdentityGcpAuthServiceFactory = ReturnType<typeof identityGcpAuthServiceFactory>;
|
export type TIdentityGcpAuthServiceFactory = ReturnType<typeof identityGcpAuthServiceFactory>;
|
||||||
|
|
||||||
export const identityGcpAuthServiceFactory = ({
|
export const identityGcpAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityGcpAuthDAL,
|
identityGcpAuthDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
@@ -55,13 +64,8 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: "GCP auth method not found for identity, did you configure GCP auth?" });
|
throw new NotFoundError({ message: "GCP auth method not found for identity, did you configure GCP auth?" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
const identity = await identityDAL.findById(identityGcpAuth.identityId);
|
||||||
actorIdentityId: identityGcpAuth.identityId,
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
if (!identityMembershipOrg) {
|
|
||||||
throw new UnauthorizedError({ message: "Identity does not belong to any organization" });
|
|
||||||
}
|
|
||||||
|
|
||||||
let gcpIdentityDetails: TGcpIdentityDetails;
|
let gcpIdentityDetails: TGcpIdentityDetails;
|
||||||
switch (identityGcpAuth.type) {
|
switch (identityGcpAuth.type) {
|
||||||
@@ -125,8 +129,8 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const identityAccessToken = await identityGcpAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityGcpAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.GCP_AUTH,
|
lastLoginAuthMethod: IdentityAuthMethod.GCP_AUTH,
|
||||||
lastLoginTime: new Date()
|
lastLoginTime: new Date()
|
||||||
@@ -164,7 +168,7 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { accessToken, identityGcpAuth, identityAccessToken, identityMembershipOrg };
|
return { accessToken, identityGcpAuth, identityAccessToken, identity };
|
||||||
};
|
};
|
||||||
|
|
||||||
const attachGcpAuth = async ({
|
const attachGcpAuth = async ({
|
||||||
@@ -193,6 +197,9 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.GCP_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.GCP_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -204,13 +211,14 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -274,6 +282,9 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.GCP_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.GCP_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -290,13 +301,14 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -345,6 +357,9 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.GCP_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.GCP_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -354,13 +369,14 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
|
|
||||||
const identityGcpAuth = await identityGcpAuthDAL.findOne({ identityId });
|
const identityGcpAuth = await identityGcpAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
return { ...identityGcpAuth, orgId: identityMembershipOrg.scopeOrgId };
|
return { ...identityGcpAuth, orgId: identityMembershipOrg.scopeOrgId };
|
||||||
@@ -381,28 +397,33 @@ export const identityGcpAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.GCP_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.GCP_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have gcp auth"
|
message: "The identity does not have gcp auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
scope: OrganizationActionScope.Any,
|
||||||
identityMembershipOrg.identity.id,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.scopeOrgId,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import https from "https";
|
|||||||
import jwt from "jsonwebtoken";
|
import jwt from "jsonwebtoken";
|
||||||
import { JwksClient } from "jwks-rsa";
|
import { JwksClient } from "jwks-rsa";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod, TIdentityJwtAuthsUpdate } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope, TIdentityJwtAuthsUpdate } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -24,6 +24,7 @@ import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
|||||||
import { getValueByDot } from "@app/lib/template/dot-access";
|
import { getValueByDot } from "@app/lib/template/dot-access";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||||
@@ -43,8 +44,9 @@ import {
|
|||||||
} from "./identity-jwt-auth-types";
|
} from "./identity-jwt-auth-types";
|
||||||
|
|
||||||
type TIdentityJwtAuthServiceFactoryDep = {
|
type TIdentityJwtAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityJwtAuthDAL: TIdentityJwtAuthDALFactory;
|
identityJwtAuthDAL: TIdentityJwtAuthDALFactory;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
@@ -55,6 +57,7 @@ type TIdentityJwtAuthServiceFactoryDep = {
|
|||||||
export type TIdentityJwtAuthServiceFactory = ReturnType<typeof identityJwtAuthServiceFactory>;
|
export type TIdentityJwtAuthServiceFactory = ReturnType<typeof identityJwtAuthServiceFactory>;
|
||||||
|
|
||||||
export const identityJwtAuthServiceFactory = ({
|
export const identityJwtAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityJwtAuthDAL,
|
identityJwtAuthDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
@@ -69,19 +72,12 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: "JWT auth method not found for identity, did you configure JWT auth?" });
|
throw new NotFoundError({ message: "JWT auth method not found for identity, did you configure JWT auth?" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
const identity = await identityDAL.findById(identityJwtAuth.identityId);
|
||||||
actorIdentityId: identityJwtAuth.identityId,
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
if (!identityMembershipOrg) {
|
|
||||||
throw new NotFoundError({
|
|
||||||
message: `Identity organization membership for identity with ID '${identityJwtAuth.identityId}' not found`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { decryptor: orgDataKeyDecryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor: orgDataKeyDecryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.Organization,
|
type: KmsDataKey.Organization,
|
||||||
orgId: identityMembershipOrg.scopeOrgId
|
orgId: identity.orgId
|
||||||
});
|
});
|
||||||
|
|
||||||
const decodedToken = crypto.jwt().decode(jwtValue, { complete: true });
|
const decodedToken = crypto.jwt().decode(jwtValue, { complete: true });
|
||||||
@@ -211,12 +207,9 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const identityAccessToken = await identityJwtAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityJwtAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{ lastLoginAuthMethod: IdentityAuthMethod.JWT_AUTH, lastLoginTime: new Date() },
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.JWT_AUTH,
|
|
||||||
lastLoginTime: new Date()
|
|
||||||
},
|
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
const newToken = await identityAccessTokenDAL.create(
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
@@ -251,7 +244,7 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { accessToken, identityJwtAuth, identityAccessToken, identityMembershipOrg };
|
return { accessToken, identityJwtAuth, identityAccessToken, identity };
|
||||||
};
|
};
|
||||||
|
|
||||||
const attachJwtAuth = async ({
|
const attachJwtAuth = async ({
|
||||||
@@ -284,6 +277,9 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.JWT_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.JWT_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Failed to add JWT Auth to already configured identity"
|
message: "Failed to add JWT Auth to already configured identity"
|
||||||
@@ -294,13 +290,14 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
@@ -387,6 +384,9 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.JWT_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.JWT_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -403,13 +403,14 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
@@ -491,6 +492,9 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.JWT_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.JWT_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -498,13 +502,14 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
@@ -539,6 +544,9 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
if (!identityMembershipOrg) {
|
if (!identityMembershipOrg) {
|
||||||
throw new NotFoundError({ message: "Failed to find identity" });
|
throw new NotFoundError({ message: "Failed to find identity" });
|
||||||
}
|
}
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.JWT_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.JWT_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -546,23 +554,25 @@ export const identityJwtAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
scope: OrganizationActionScope.Any,
|
||||||
identityMembershipOrg.identity.id,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.scopeOrgId,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
|
|||||||
@@ -3,7 +3,12 @@ import axios, { AxiosError } from "axios";
|
|||||||
import https from "https";
|
import https from "https";
|
||||||
import RE2 from "re2";
|
import RE2 from "re2";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod, TIdentityKubernetesAuthsUpdate } from "@app/db/schemas";
|
import {
|
||||||
|
AccessScope,
|
||||||
|
IdentityAuthMethod,
|
||||||
|
OrganizationActionScope,
|
||||||
|
TIdentityKubernetesAuthsUpdate
|
||||||
|
} from "@app/db/schemas";
|
||||||
import { TGatewayDALFactory } from "@app/ee/services/gateway/gateway-dal";
|
import { TGatewayDALFactory } from "@app/ee/services/gateway/gateway-dal";
|
||||||
import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service";
|
import { TGatewayServiceFactory } from "@app/ee/services/gateway/gateway-service";
|
||||||
import { TGatewayV2DALFactory } from "@app/ee/services/gateway-v2/gateway-v2-dal";
|
import { TGatewayV2DALFactory } from "@app/ee/services/gateway-v2/gateway-v2-dal";
|
||||||
@@ -21,13 +26,20 @@ import {
|
|||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
|
NotFoundError,
|
||||||
|
PermissionBoundaryError,
|
||||||
|
UnauthorizedError
|
||||||
|
} from "@app/lib/errors";
|
||||||
import { GatewayHttpProxyActions, GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway";
|
import { GatewayHttpProxyActions, GatewayProxyProtocol, withGatewayProxy } from "@app/lib/gateway";
|
||||||
import { withGatewayV2Proxy } from "@app/lib/gateway-v2/gateway-v2";
|
import { withGatewayV2Proxy } from "@app/lib/gateway-v2/gateway-v2";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||||
@@ -48,12 +60,13 @@ import {
|
|||||||
} from "./identity-kubernetes-auth-types";
|
} from "./identity-kubernetes-auth-types";
|
||||||
|
|
||||||
type TIdentityKubernetesAuthServiceFactoryDep = {
|
type TIdentityKubernetesAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityKubernetesAuthDAL: Pick<
|
identityKubernetesAuthDAL: Pick<
|
||||||
TIdentityKubernetesAuthDALFactory,
|
TIdentityKubernetesAuthDALFactory,
|
||||||
"create" | "findOne" | "transaction" | "updateById" | "delete"
|
"create" | "findOne" | "transaction" | "updateById" | "delete"
|
||||||
>;
|
>;
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||||
@@ -69,6 +82,7 @@ export type TIdentityKubernetesAuthServiceFactory = ReturnType<typeof identityKu
|
|||||||
const GATEWAY_AUTH_DEFAULT_HOST = "https://kubernetes.default.svc.cluster.local";
|
const GATEWAY_AUTH_DEFAULT_HOST = "https://kubernetes.default.svc.cluster.local";
|
||||||
|
|
||||||
export const identityKubernetesAuthServiceFactory = ({
|
export const identityKubernetesAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityKubernetesAuthDAL,
|
identityKubernetesAuthDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
@@ -175,19 +189,12 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
const identity = await identityDAL.findById(identityKubernetesAuth.identityId);
|
||||||
actorIdentityId: identityKubernetesAuth.identityId,
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
if (!identityMembershipOrg) {
|
|
||||||
throw new NotFoundError({
|
|
||||||
message: `Identity organization membership for identity with ID '${identityKubernetesAuth.identityId}' not found`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.Organization,
|
type: KmsDataKey.Organization,
|
||||||
orgId: identityMembershipOrg.scopeOrgId
|
orgId: identity.orgId
|
||||||
});
|
});
|
||||||
|
|
||||||
let caCert = "";
|
let caCert = "";
|
||||||
@@ -430,12 +437,9 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const identityAccessToken = await identityKubernetesAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityKubernetesAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{ lastLoginAuthMethod: IdentityAuthMethod.KUBERNETES_AUTH, lastLoginTime: new Date() },
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.KUBERNETES_AUTH,
|
|
||||||
lastLoginTime: new Date()
|
|
||||||
},
|
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
const newToken = await identityAccessTokenDAL.create(
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
@@ -475,7 +479,7 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { accessToken, identityKubernetesAuth, identityAccessToken, identityMembershipOrg };
|
return { accessToken, identityKubernetesAuth, identityAccessToken, identity };
|
||||||
};
|
};
|
||||||
|
|
||||||
const attachKubernetesAuth = async ({
|
const attachKubernetesAuth = async ({
|
||||||
@@ -508,6 +512,9 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.KUBERNETES_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.KUBERNETES_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -519,13 +526,14 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -560,13 +568,14 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
isGatewayV1 = false;
|
isGatewayV1 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission: orgPermission } = await permissionService.getOrgPermission(
|
const { permission: orgPermission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(orgPermission).throwUnlessCan(
|
ForbiddenError.from(orgPermission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.AttachGateways,
|
OrgPermissionGatewayActions.AttachGateways,
|
||||||
OrgPermissionSubjects.Gateway
|
OrgPermissionSubjects.Gateway
|
||||||
@@ -633,6 +642,9 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.KUBERNETES_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.KUBERNETES_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -650,13 +662,14 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -692,13 +705,14 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
isGatewayV1 = false;
|
isGatewayV1 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission: orgPermission } = await permissionService.getOrgPermission(
|
const { permission: orgPermission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(orgPermission).throwUnlessCan(
|
ForbiddenError.from(orgPermission).throwUnlessCan(
|
||||||
OrgPermissionGatewayActions.AttachGateways,
|
OrgPermissionGatewayActions.AttachGateways,
|
||||||
OrgPermissionSubjects.Gateway
|
OrgPermissionSubjects.Gateway
|
||||||
@@ -779,6 +793,9 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
const identityKubernetesAuth = await identityKubernetesAuthDAL.findOne({ identityId });
|
const identityKubernetesAuth = await identityKubernetesAuthDAL.findOne({ identityId });
|
||||||
if (!identityKubernetesAuth) {
|
if (!identityKubernetesAuth) {
|
||||||
@@ -791,13 +808,14 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
@@ -841,28 +859,33 @@ export const identityKubernetesAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.KUBERNETES_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.KUBERNETES_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have kubernetes auth"
|
message: "The identity does not have kubernetes auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
import slugify from "@sindresorhus/slugify";
|
import slugify from "@sindresorhus/slugify";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TIdentityAuthTemplateDALFactory } from "@app/ee/services/identity-auth-template";
|
import { TIdentityAuthTemplateDALFactory } from "@app/ee/services/identity-auth-template";
|
||||||
import { testLDAPConfig } from "@app/ee/services/ldap-config/ldap-fns";
|
import { testLDAPConfig } from "@app/ee/services/ldap-config/ldap-fns";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
@@ -21,6 +21,7 @@ import { getConfig } from "@app/lib/config/env";
|
|||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import {
|
import {
|
||||||
BadRequestError,
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
NotFoundError,
|
NotFoundError,
|
||||||
PermissionBoundaryError,
|
PermissionBoundaryError,
|
||||||
RateLimitError,
|
RateLimitError,
|
||||||
@@ -56,11 +57,11 @@ type TIdentityLdapAuthServiceFactoryDep = {
|
|||||||
TIdentityLdapAuthDALFactory,
|
TIdentityLdapAuthDALFactory,
|
||||||
"findOne" | "transaction" | "create" | "updateById" | "delete"
|
"findOne" | "transaction" | "create" | "updateById" | "delete"
|
||||||
>;
|
>;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
kmsService: TKmsServiceFactory;
|
kmsService: TKmsServiceFactory;
|
||||||
identityDAL: TIdentityDALFactory;
|
identityDAL: Pick<TIdentityDALFactory, "findById" | "findOne">;
|
||||||
identityAuthTemplateDAL: TIdentityAuthTemplateDALFactory;
|
identityAuthTemplateDAL: TIdentityAuthTemplateDALFactory;
|
||||||
keyStore: Pick<
|
keyStore: Pick<
|
||||||
TKeyStoreFactory,
|
TKeyStoreFactory,
|
||||||
@@ -150,17 +151,6 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const login = async ({ identityId }: TLoginLdapAuthDTO) => {
|
const login = async ({ identityId }: TLoginLdapAuthDTO) => {
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
|
||||||
actorIdentityId: identityId,
|
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!identityMembershipOrg) {
|
|
||||||
throw new UnauthorizedError({
|
|
||||||
message: "Invalid credentials"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const identityLdapAuth = await identityLdapAuthDAL.findOne({ identityId });
|
const identityLdapAuth = await identityLdapAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
if (!identityLdapAuth) {
|
if (!identityLdapAuth) {
|
||||||
@@ -169,7 +159,10 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const identity = await identityDAL.findById(identityLdapAuth.identityId);
|
||||||
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
|
|
||||||
|
const plan = await licenseService.getPlan(identity.orgId);
|
||||||
if (!plan.ldap) {
|
if (!plan.ldap) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message:
|
message:
|
||||||
@@ -178,12 +171,9 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const identityAccessToken = await identityLdapAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityLdapAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{ lastLoginAuthMethod: IdentityAuthMethod.LDAP_AUTH, lastLoginTime: new Date() },
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.LDAP_AUTH,
|
|
||||||
lastLoginTime: new Date()
|
|
||||||
},
|
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
const newToken = await identityAccessTokenDAL.create(
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
@@ -217,7 +207,7 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { accessToken, identityLdapAuth, identityAccessToken, identityMembershipOrg };
|
return { accessToken, identityLdapAuth, identityAccessToken, identity };
|
||||||
};
|
};
|
||||||
|
|
||||||
const attachLdapAuth = async ({
|
const attachLdapAuth = async ({
|
||||||
@@ -254,6 +244,9 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.LDAP_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.LDAP_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -265,13 +258,14 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
if (templateId) {
|
if (templateId) {
|
||||||
@@ -425,6 +419,9 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.LDAP_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.LDAP_AUTH)) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
@@ -441,13 +438,14 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
if (templateId) {
|
if (templateId) {
|
||||||
@@ -588,6 +586,9 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.LDAP_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.LDAP_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -597,13 +598,14 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
|
|
||||||
const ldapIdentityAuth = await identityLdapAuthDAL.findOne({ identityId });
|
const ldapIdentityAuth = await identityLdapAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.Organization,
|
type: KmsDataKey.Organization,
|
||||||
@@ -635,27 +637,32 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.LDAP_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.LDAP_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have LDAP Auth attached"
|
message: "The identity does not have LDAP Auth attached"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
@@ -785,13 +792,14 @@ export const identityLdapAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const deleted = await keyStore.deleteItems({
|
const deleted = await keyStore.deleteItems({
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { ForbiddenError } from "@casl/ability";
|
|||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
import RE2 from "re2";
|
import RE2 from "re2";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -14,11 +14,18 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
|||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { request } from "@app/lib/config/request";
|
import { request } from "@app/lib/config/request";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
|
NotFoundError,
|
||||||
|
PermissionBoundaryError,
|
||||||
|
UnauthorizedError
|
||||||
|
} from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
@@ -35,9 +42,10 @@ import {
|
|||||||
} from "./identity-oci-auth-types";
|
} from "./identity-oci-auth-types";
|
||||||
|
|
||||||
type TIdentityOciAuthServiceFactoryDep = {
|
type TIdentityOciAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
identityOciAuthDAL: Pick<TIdentityOciAuthDALFactory, "findOne" | "transaction" | "create" | "updateById" | "delete">;
|
identityOciAuthDAL: Pick<TIdentityOciAuthDALFactory, "findOne" | "transaction" | "create" | "updateById" | "delete">;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||||
@@ -46,6 +54,7 @@ type TIdentityOciAuthServiceFactoryDep = {
|
|||||||
export type TIdentityOciAuthServiceFactory = ReturnType<typeof identityOciAuthServiceFactory>;
|
export type TIdentityOciAuthServiceFactory = ReturnType<typeof identityOciAuthServiceFactory>;
|
||||||
|
|
||||||
export const identityOciAuthServiceFactory = ({
|
export const identityOciAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityOciAuthDAL,
|
identityOciAuthDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
@@ -59,11 +68,8 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: "OCI auth method not found for identity, did you configure OCI auth?" });
|
throw new NotFoundError({ message: "OCI auth method not found for identity, did you configure OCI auth?" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
const identity = await identityDAL.findById(identityOciAuth.identityId);
|
||||||
actorIdentityId: identityOciAuth.identityId,
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
if (!identityMembershipOrg) throw new UnauthorizedError({ message: "Identity not attached to a organization" });
|
|
||||||
|
|
||||||
// Validate OCI host format. Ensures that the host is in "identity.<region>.oraclecloud.com" format.
|
// Validate OCI host format. Ensures that the host is in "identity.<region>.oraclecloud.com" format.
|
||||||
if (!headers.host || !new RE2("^identity\\.([a-z]{2}-[a-z]+-[1-9])\\.oraclecloud\\.com$").test(headers.host)) {
|
if (!headers.host || !new RE2("^identity\\.([a-z]{2}-[a-z]+-[1-9])\\.oraclecloud\\.com$").test(headers.host)) {
|
||||||
@@ -98,12 +104,9 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
|
|
||||||
// Generate the token
|
// Generate the token
|
||||||
const identityAccessToken = await identityOciAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityOciAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{ lastLoginAuthMethod: IdentityAuthMethod.OCI_AUTH, lastLoginTime: new Date() },
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.OCI_AUTH,
|
|
||||||
lastLoginTime: new Date()
|
|
||||||
},
|
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
const newToken = await identityAccessTokenDAL.create(
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
@@ -140,7 +143,7 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
identityOciAuth,
|
identityOciAuth,
|
||||||
accessToken,
|
accessToken,
|
||||||
identityAccessToken,
|
identityAccessToken,
|
||||||
identityMembershipOrg
|
identity
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -168,6 +171,9 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OCI_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OCI_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -179,13 +185,14 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -246,6 +253,9 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OCI_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OCI_AUTH)) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
@@ -262,13 +272,14 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -312,6 +323,9 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OCI_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OCI_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -321,13 +335,14 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
|
|
||||||
const ociIdentityAuth = await identityOciAuthDAL.findOne({ identityId });
|
const ociIdentityAuth = await identityOciAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
return { ...ociIdentityAuth, orgId: identityMembershipOrg.scopeOrgId };
|
return { ...ociIdentityAuth, orgId: identityMembershipOrg.scopeOrgId };
|
||||||
};
|
};
|
||||||
@@ -347,27 +362,32 @@ export const identityOciAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OCI_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OCI_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have OCI auth"
|
message: "The identity does not have OCI auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(actorOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(actorOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import https from "https";
|
|||||||
import jwt from "jsonwebtoken";
|
import jwt from "jsonwebtoken";
|
||||||
import { JwksClient } from "jwks-rsa";
|
import { JwksClient } from "jwks-rsa";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod, TIdentityOidcAuthsUpdate } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope, TIdentityOidcAuthsUpdate } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -25,6 +25,7 @@ import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
|||||||
import { getValueByDot } from "@app/lib/template/dot-access";
|
import { getValueByDot } from "@app/lib/template/dot-access";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||||
@@ -43,8 +44,9 @@ import {
|
|||||||
} from "./identity-oidc-auth-types";
|
} from "./identity-oidc-auth-types";
|
||||||
|
|
||||||
type TIdentityOidcAuthServiceFactoryDep = {
|
type TIdentityOidcAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityOidcAuthDAL: TIdentityOidcAuthDALFactory;
|
identityOidcAuthDAL: TIdentityOidcAuthDALFactory;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
@@ -55,6 +57,7 @@ type TIdentityOidcAuthServiceFactoryDep = {
|
|||||||
export type TIdentityOidcAuthServiceFactory = ReturnType<typeof identityOidcAuthServiceFactory>;
|
export type TIdentityOidcAuthServiceFactory = ReturnType<typeof identityOidcAuthServiceFactory>;
|
||||||
|
|
||||||
export const identityOidcAuthServiceFactory = ({
|
export const identityOidcAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityOidcAuthDAL,
|
identityOidcAuthDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
@@ -69,19 +72,12 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: "OIDC auth method not found for identity, did you configure OIDC auth?" });
|
throw new NotFoundError({ message: "OIDC auth method not found for identity, did you configure OIDC auth?" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
const identity = await identityDAL.findById(identityOidcAuth.identityId);
|
||||||
actorIdentityId: identityOidcAuth.identityId,
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
if (!identityMembershipOrg) {
|
|
||||||
throw new NotFoundError({
|
|
||||||
message: `Identity organization membership for identity with ID '${identityOidcAuth.identityId}' not found`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.Organization,
|
type: KmsDataKey.Organization,
|
||||||
orgId: identityMembershipOrg.scopeOrgId
|
orgId: identity.orgId
|
||||||
});
|
});
|
||||||
|
|
||||||
let caCert = "";
|
let caCert = "";
|
||||||
@@ -182,12 +178,9 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const identityAccessToken = await identityOidcAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityOidcAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{ lastLoginAuthMethod: IdentityAuthMethod.OIDC_AUTH, lastLoginTime: new Date() },
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.OIDC_AUTH,
|
|
||||||
lastLoginTime: new Date()
|
|
||||||
},
|
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
const newToken = await identityAccessTokenDAL.create(
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
@@ -226,7 +219,7 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { accessToken, identityOidcAuth, identityAccessToken, identityMembershipOrg, oidcTokenData: tokenData };
|
return { accessToken, identityOidcAuth, identityAccessToken, identity, oidcTokenData: tokenData };
|
||||||
};
|
};
|
||||||
|
|
||||||
const attachOidcAuth = async ({
|
const attachOidcAuth = async ({
|
||||||
@@ -259,6 +252,9 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
if (!identityMembershipOrg) {
|
if (!identityMembershipOrg) {
|
||||||
throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
}
|
}
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Failed to add OIDC Auth to already configured identity"
|
message: "Failed to add OIDC Auth to already configured identity"
|
||||||
@@ -269,13 +265,14 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
@@ -351,6 +348,9 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -367,13 +367,14 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
@@ -440,6 +441,9 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -447,13 +451,14 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const identityOidcAuth = await identityOidcAuthDAL.findOne({ identityId });
|
const identityOidcAuth = await identityOidcAuthDAL.findOne({ identityId });
|
||||||
@@ -481,6 +486,9 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
if (!identityMembershipOrg) {
|
if (!identityMembershipOrg) {
|
||||||
throw new NotFoundError({ message: "Failed to find identity" });
|
throw new NotFoundError({ message: "Failed to find identity" });
|
||||||
}
|
}
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.OIDC_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -488,23 +496,25 @@ export const identityOidcAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
|
|||||||
@@ -25,11 +25,12 @@ import { buildAuthMethods } from "../identity/identity-fns";
|
|||||||
export type TIdentityProjectDALFactory = ReturnType<typeof identityProjectDALFactory>;
|
export type TIdentityProjectDALFactory = ReturnType<typeof identityProjectDALFactory>;
|
||||||
|
|
||||||
export const identityProjectDALFactory = (db: TDbClient) => {
|
export const identityProjectDALFactory = (db: TDbClient) => {
|
||||||
const findByIdentityId = async (identityId: string, tx?: Knex) => {
|
const findByIdentityId = async (identityId: string, orgId: string, tx?: Knex) => {
|
||||||
try {
|
try {
|
||||||
const docs = await (tx || db.replicaNode())(TableName.Membership)
|
const docs = await (tx || db.replicaNode())(TableName.Membership)
|
||||||
.where(`${TableName.Membership}.actorIdentityId`, identityId)
|
.where(`${TableName.Membership}.actorIdentityId`, identityId)
|
||||||
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
.where(`${TableName.Membership}.scope`, AccessScope.Project)
|
||||||
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
.join(TableName.Project, `${TableName.Membership}.scopeProjectId`, `${TableName.Project}.id`)
|
||||||
.join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
|
.join(TableName.Identity, `${TableName.Membership}.actorIdentityId`, `${TableName.Identity}.id`)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -11,10 +11,17 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
|||||||
import { extractX509CertFromChain } from "@app/lib/certificates/extract-certificate";
|
import { extractX509CertFromChain } from "@app/lib/certificates/extract-certificate";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError, UnauthorizedError } from "@app/lib/errors";
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
|
NotFoundError,
|
||||||
|
PermissionBoundaryError,
|
||||||
|
UnauthorizedError
|
||||||
|
} from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||||
@@ -25,12 +32,13 @@ import { TIdentityTlsCertAuthDALFactory } from "./identity-tls-cert-auth-dal";
|
|||||||
import { TIdentityTlsCertAuthServiceFactory } from "./identity-tls-cert-auth-types";
|
import { TIdentityTlsCertAuthServiceFactory } from "./identity-tls-cert-auth-types";
|
||||||
|
|
||||||
type TIdentityTlsCertAuthServiceFactoryDep = {
|
type TIdentityTlsCertAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
identityAccessTokenDAL: Pick<TIdentityAccessTokenDALFactory, "create" | "delete">;
|
||||||
identityTlsCertAuthDAL: Pick<
|
identityTlsCertAuthDAL: Pick<
|
||||||
TIdentityTlsCertAuthDALFactory,
|
TIdentityTlsCertAuthDALFactory,
|
||||||
"findOne" | "transaction" | "create" | "updateById" | "delete"
|
"findOne" | "transaction" | "create" | "updateById" | "delete"
|
||||||
>;
|
>;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
|
||||||
@@ -46,6 +54,7 @@ const parseSubjectDetails = (data: string) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const identityTlsCertAuthServiceFactory = ({
|
export const identityTlsCertAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
identityTlsCertAuthDAL,
|
identityTlsCertAuthDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
@@ -61,20 +70,12 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
const identity = await identityDAL.findById(identityTlsCertAuth.identityId);
|
||||||
actorIdentityId: identityTlsCertAuth.identityId,
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!identityMembershipOrg) {
|
|
||||||
throw new NotFoundError({
|
|
||||||
message: `Identity organization membership for identity with ID '${identityTlsCertAuth.identityId}' not found`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.Organization,
|
type: KmsDataKey.Organization,
|
||||||
orgId: identityMembershipOrg.scopeOrgId
|
orgId: identity.orgId
|
||||||
});
|
});
|
||||||
|
|
||||||
const caCertificate = decryptor({
|
const caCertificate = decryptor({
|
||||||
@@ -119,12 +120,9 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
|
|
||||||
// Generate the token
|
// Generate the token
|
||||||
const identityAccessToken = await identityTlsCertAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityTlsCertAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{ lastLoginAuthMethod: IdentityAuthMethod.TLS_CERT_AUTH, lastLoginTime: new Date() },
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.TLS_CERT_AUTH,
|
|
||||||
lastLoginTime: new Date()
|
|
||||||
},
|
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
const newToken = await identityAccessTokenDAL.create(
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
@@ -161,7 +159,7 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
identityTlsCertAuth,
|
identityTlsCertAuth,
|
||||||
accessToken,
|
accessToken,
|
||||||
identityAccessToken,
|
identityAccessToken,
|
||||||
identityMembershipOrg
|
identity
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -189,6 +187,9 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -200,13 +201,14 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -271,6 +273,9 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
||||||
throw new NotFoundError({
|
throw new NotFoundError({
|
||||||
@@ -288,13 +293,14 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -350,6 +356,9 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -359,13 +368,14 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
|
|
||||||
const identityAuth = await identityTlsCertAuthDAL.findOne({ identityId });
|
const identityAuth = await identityTlsCertAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
const { decryptor } = await kmsService.createCipherPairWithDataKey({
|
||||||
type: KmsDataKey.Organization,
|
type: KmsDataKey.Organization,
|
||||||
@@ -394,28 +404,32 @@ export const identityTlsCertAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TLS_CERT_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have TLS Certificate auth"
|
message: "The identity does not have TLS Certificate auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission, memberships } = await permissionService.getOrgPermission(
|
const { permission: rolePermission, memberships } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
const shouldUseNewPrivilegeSystem = Boolean(memberships?.[0]?.shouldUseNewPrivilegeSystem);
|
const shouldUseNewPrivilegeSystem = Boolean(memberships?.[0]?.shouldUseNewPrivilegeSystem);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { TIdentityAccessTokens, TIdentityTlsCertAuths, TMemberships } from "@app/db/schemas";
|
import { TIdentities, TIdentityAccessTokens, TIdentityTlsCertAuths } from "@app/db/schemas";
|
||||||
import { TProjectPermission } from "@app/lib/types";
|
import { TProjectPermission } from "@app/lib/types";
|
||||||
|
|
||||||
export type TLoginTlsCertAuthDTO = {
|
export type TLoginTlsCertAuthDTO = {
|
||||||
@@ -40,7 +40,7 @@ export type TIdentityTlsCertAuthServiceFactory = {
|
|||||||
identityTlsCertAuth: TIdentityTlsCertAuths;
|
identityTlsCertAuth: TIdentityTlsCertAuths;
|
||||||
accessToken: string;
|
accessToken: string;
|
||||||
identityAccessToken: TIdentityAccessTokens;
|
identityAccessToken: TIdentityAccessTokens;
|
||||||
identityMembershipOrg: TMemberships;
|
identity: TIdentities;
|
||||||
}>;
|
}>;
|
||||||
attachTlsCertAuth: (dto: TAttachTlsCertAuthDTO) => Promise<TIdentityTlsCertAuths>;
|
attachTlsCertAuth: (dto: TAttachTlsCertAuthDTO) => Promise<TIdentityTlsCertAuths>;
|
||||||
updateTlsCertAuth: (dto: TUpdateTlsCertAuthDTO) => Promise<TIdentityTlsCertAuths>;
|
updateTlsCertAuth: (dto: TUpdateTlsCertAuthDTO) => Promise<TIdentityTlsCertAuths>;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod, TableName } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope, TableName } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -10,10 +10,17 @@ import {
|
|||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { getConfig } from "@app/lib/config/env";
|
import { getConfig } from "@app/lib/config/env";
|
||||||
import { crypto } from "@app/lib/crypto";
|
import { crypto } from "@app/lib/crypto";
|
||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
|
import {
|
||||||
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
|
NotFoundError,
|
||||||
|
PermissionBoundaryError,
|
||||||
|
UnauthorizedError
|
||||||
|
} from "@app/lib/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "@app/lib/ip";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
@@ -32,11 +39,12 @@ import {
|
|||||||
} from "./identity-token-auth-types";
|
} from "./identity-token-auth-types";
|
||||||
|
|
||||||
type TIdentityTokenAuthServiceFactoryDep = {
|
type TIdentityTokenAuthServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityTokenAuthDAL: Pick<
|
identityTokenAuthDAL: Pick<
|
||||||
TIdentityTokenAuthDALFactory,
|
TIdentityTokenAuthDALFactory,
|
||||||
"transaction" | "create" | "findOne" | "updateById" | "delete"
|
"transaction" | "create" | "findOne" | "updateById" | "delete"
|
||||||
>;
|
>;
|
||||||
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "updateById" | "getIdentityById">;
|
membershipIdentityDAL: Pick<TMembershipIdentityDALFactory, "findOne" | "update" | "getIdentityById">;
|
||||||
identityAccessTokenDAL: Pick<
|
identityAccessTokenDAL: Pick<
|
||||||
TIdentityAccessTokenDALFactory,
|
TIdentityAccessTokenDALFactory,
|
||||||
"create" | "find" | "update" | "findById" | "findOne" | "updateById" | "delete"
|
"create" | "find" | "update" | "findById" | "findOne" | "updateById" | "delete"
|
||||||
@@ -49,8 +57,8 @@ type TIdentityTokenAuthServiceFactoryDep = {
|
|||||||
export type TIdentityTokenAuthServiceFactory = ReturnType<typeof identityTokenAuthServiceFactory>;
|
export type TIdentityTokenAuthServiceFactory = ReturnType<typeof identityTokenAuthServiceFactory>;
|
||||||
|
|
||||||
export const identityTokenAuthServiceFactory = ({
|
export const identityTokenAuthServiceFactory = ({
|
||||||
|
identityDAL,
|
||||||
identityTokenAuthDAL,
|
identityTokenAuthDAL,
|
||||||
// identityDAL,
|
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
identityAccessTokenDAL,
|
identityAccessTokenDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
@@ -79,6 +87,9 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
|
if (identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -90,13 +101,14 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -155,6 +167,9 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -172,13 +187,14 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -223,6 +239,9 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
@@ -232,13 +251,14 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
|
|
||||||
const identityTokenAuth = await identityTokenAuthDAL.findOne({ identityId });
|
const identityTokenAuth = await identityTokenAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
return { ...identityTokenAuth, orgId: identityMembershipOrg.scopeOrgId };
|
return { ...identityTokenAuth, orgId: identityMembershipOrg.scopeOrgId };
|
||||||
@@ -262,28 +282,33 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
identityId
|
identityId
|
||||||
});
|
});
|
||||||
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityMembershipOrg) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
|
if (!identityMembershipOrg.identity.authMethods.includes(IdentityAuthMethod.TOKEN_AUTH)) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "The identity does not have Token Auth"
|
message: "The identity does not have Token Auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
@@ -341,22 +366,26 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
message: "The identity does not have Token Auth"
|
message: "The identity does not have Token Auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
|
||||||
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
@@ -379,13 +408,13 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
|
|
||||||
const identityTokenAuth = await identityTokenAuthDAL.findOne({ identityId });
|
const identityTokenAuth = await identityTokenAuthDAL.findOne({ identityId });
|
||||||
|
|
||||||
|
const identity = await identityDAL.findById(identityTokenAuth.identityId);
|
||||||
|
if (!identity) throw new UnauthorizedError({ message: "Identity not found" });
|
||||||
|
|
||||||
const identityAccessToken = await identityTokenAuthDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityTokenAuthDAL.transaction(async (tx) => {
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{ lastLoginAuthMethod: IdentityAuthMethod.TOKEN_AUTH, lastLoginTime: new Date() },
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.TOKEN_AUTH,
|
|
||||||
lastLoginTime: new Date()
|
|
||||||
},
|
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
const newToken = await identityAccessTokenDAL.create(
|
const newToken = await identityAccessTokenDAL.create(
|
||||||
@@ -420,7 +449,7 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return { accessToken, identityTokenAuth, identityAccessToken, identityMembershipOrg };
|
return { accessToken, identityTokenAuth, identityAccessToken, identity };
|
||||||
};
|
};
|
||||||
|
|
||||||
const getTokenAuthTokens = async ({
|
const getTokenAuthTokens = async ({
|
||||||
@@ -449,13 +478,14 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
message: "The identity does not have Token Auth"
|
message: "The identity does not have Token Auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const tokens = await identityAccessTokenDAL.find(
|
const tokens = await identityAccessTokenDAL.find(
|
||||||
@@ -501,22 +531,24 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
message: "The identity does not have Token Auth"
|
message: "The identity does not have Token Auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
@@ -580,13 +612,14 @@ export const identityTokenAuthServiceFactory = ({
|
|||||||
throw new NotFoundError({ message: `Failed to find identity with ID ${identityAccessToken.identityId}` });
|
throw new NotFoundError({ message: `Failed to find identity with ID ${identityAccessToken.identityId}` });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityOrgMembership.scopeOrgId,
|
orgId: identityOrgMembership.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const [revokedToken] = await identityAccessTokenDAL.update(
|
const [revokedToken] = await identityAccessTokenDAL.update(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope, IdentityAuthMethod } from "@app/db/schemas";
|
import { AccessScope, IdentityAuthMethod, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -13,6 +13,7 @@ import { getConfig } from "@app/lib/config/env";
|
|||||||
import { crypto } from "@app/lib/crypto/cryptography";
|
import { crypto } from "@app/lib/crypto/cryptography";
|
||||||
import {
|
import {
|
||||||
BadRequestError,
|
BadRequestError,
|
||||||
|
ForbiddenRequestError,
|
||||||
NotFoundError,
|
NotFoundError,
|
||||||
PermissionBoundaryError,
|
PermissionBoundaryError,
|
||||||
RateLimitError,
|
RateLimitError,
|
||||||
@@ -22,6 +23,7 @@ import { checkIPAgainstBlocklist, extractIPDetails, isValidIpOrCidr, TIp } from
|
|||||||
import { logger } from "@app/lib/logger";
|
import { logger } from "@app/lib/logger";
|
||||||
|
|
||||||
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
import { ActorType, AuthTokenType } from "../auth/auth-type";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
import { TIdentityAccessTokenDALFactory } from "../identity-access-token/identity-access-token-dal";
|
||||||
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
import { TIdentityAccessTokenJwtPayload } from "../identity-access-token/identity-access-token-types";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
@@ -42,6 +44,7 @@ import {
|
|||||||
} from "./identity-ua-types";
|
} from "./identity-ua-types";
|
||||||
|
|
||||||
type TIdentityUaServiceFactoryDep = {
|
type TIdentityUaServiceFactoryDep = {
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
identityUaDAL: TIdentityUaDALFactory;
|
identityUaDAL: TIdentityUaDALFactory;
|
||||||
identityUaClientSecretDAL: TIdentityUaClientSecretDALFactory;
|
identityUaClientSecretDAL: TIdentityUaClientSecretDALFactory;
|
||||||
identityAccessTokenDAL: TIdentityAccessTokenDALFactory;
|
identityAccessTokenDAL: TIdentityAccessTokenDALFactory;
|
||||||
@@ -70,7 +73,8 @@ export const identityUaServiceFactory = ({
|
|||||||
permissionService,
|
permissionService,
|
||||||
licenseService,
|
licenseService,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
keyStore
|
keyStore,
|
||||||
|
identityDAL
|
||||||
}: TIdentityUaServiceFactoryDep) => {
|
}: TIdentityUaServiceFactoryDep) => {
|
||||||
const login = async (clientId: string, clientSecret: string, ip: string) => {
|
const login = async (clientId: string, clientSecret: string, ip: string) => {
|
||||||
const identityUa = await identityUaDAL.findOne({ clientId });
|
const identityUa = await identityUaDAL.findOne({ clientId });
|
||||||
@@ -100,16 +104,6 @@ export const identityUaServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const identityMembershipOrg = await membershipIdentityDAL.findOne({
|
|
||||||
actorIdentityId: identityUa.identityId,
|
|
||||||
scope: AccessScope.Organization
|
|
||||||
});
|
|
||||||
if (!identityMembershipOrg) {
|
|
||||||
throw new UnauthorizedError({
|
|
||||||
message: "Invalid credentials"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const clientSecretPrefix = clientSecret.slice(0, 4);
|
const clientSecretPrefix = clientSecret.slice(0, 4);
|
||||||
const clientSecretInfo = await identityUaClientSecretDAL.find({
|
const clientSecretInfo = await identityUaClientSecretDAL.find({
|
||||||
identityUAId: identityUa.id,
|
identityUAId: identityUa.id,
|
||||||
@@ -227,10 +221,11 @@ export const identityUaServiceFactory = ({
|
|||||||
accessTokenMaxTTL: 1000000000
|
accessTokenMaxTTL: 1000000000
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const identity = await identityDAL.findById(identityUa.identityId);
|
||||||
const identityAccessToken = await identityUaDAL.transaction(async (tx) => {
|
const identityAccessToken = await identityUaDAL.transaction(async (tx) => {
|
||||||
const uaClientSecretDoc = await identityUaClientSecretDAL.incrementUsage(validClientSecretInfo!.id, tx);
|
const uaClientSecretDoc = await identityUaClientSecretDAL.incrementUsage(validClientSecretInfo!.id, tx);
|
||||||
await membershipIdentityDAL.updateById(
|
await membershipIdentityDAL.update(
|
||||||
identityMembershipOrg.id,
|
{ scope: AccessScope.Organization, scopeOrgId: identity.orgId, actorIdentityId: identity.id },
|
||||||
{
|
{
|
||||||
lastLoginAuthMethod: IdentityAuthMethod.UNIVERSAL_AUTH,
|
lastLoginAuthMethod: IdentityAuthMethod.UNIVERSAL_AUTH,
|
||||||
lastLoginTime: new Date()
|
lastLoginTime: new Date()
|
||||||
@@ -276,7 +271,7 @@ export const identityUaServiceFactory = ({
|
|||||||
identityUa,
|
identityUa,
|
||||||
validClientSecretInfo,
|
validClientSecretInfo,
|
||||||
identityAccessToken,
|
identityAccessToken,
|
||||||
identityMembershipOrg,
|
identity,
|
||||||
...accessTokenTTLParams
|
...accessTokenTTLParams
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -315,18 +310,23 @@ export const identityUaServiceFactory = ({
|
|||||||
message: "Failed to add universal auth to already configured identity"
|
message: "Failed to add universal auth to already configured identity"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (accessTokenMaxTTL > 0 && accessTokenTTL > accessTokenMaxTTL) {
|
if (accessTokenMaxTTL > 0 && accessTokenTTL > accessTokenMaxTTL) {
|
||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -423,6 +423,10 @@ export const identityUaServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL) > 0 &&
|
(accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL) > 0 &&
|
||||||
(accessTokenTTL || uaIdentityAuth.accessTokenMaxTTL) > (accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL)
|
(accessTokenTTL || uaIdentityAuth.accessTokenMaxTTL) > (accessTokenMaxTTL || uaIdentityAuth.accessTokenMaxTTL)
|
||||||
@@ -430,13 +434,14 @@ export const identityUaServiceFactory = ({
|
|||||||
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
throw new BadRequestError({ message: "Access token TTL cannot be greater than max TTL" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
const plan = await licenseService.getPlan(identityMembershipOrg.scopeOrgId);
|
||||||
@@ -512,14 +517,18 @@ export const identityUaServiceFactory = ({
|
|||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
return { ...uaIdentityAuth, orgId: identityMembershipOrg.scopeOrgId };
|
return { ...uaIdentityAuth, orgId: identityMembershipOrg.scopeOrgId };
|
||||||
};
|
};
|
||||||
@@ -545,22 +554,27 @@ export const identityUaServiceFactory = ({
|
|||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
@@ -611,23 +625,28 @@ export const identityUaServiceFactory = ({
|
|||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
@@ -692,23 +711,28 @@ export const identityUaServiceFactory = ({
|
|||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
@@ -761,6 +785,9 @@ export const identityUaServiceFactory = ({
|
|||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
const identityUa = await identityUaDAL.findOne({ identityId });
|
const identityUa = await identityUaDAL.findOne({ identityId });
|
||||||
if (!identityUa) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityUa) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
@@ -768,22 +795,24 @@ export const identityUaServiceFactory = ({
|
|||||||
const clientSecret = await identityUaClientSecretDAL.findOne({ id: clientSecretId, identityUAId: identityUa.id });
|
const clientSecret = await identityUaClientSecretDAL.findOne({ id: clientSecretId, identityUAId: identityUa.id });
|
||||||
if (!clientSecret) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!clientSecret) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
shouldUseNewPrivilegeSystem,
|
shouldUseNewPrivilegeSystem,
|
||||||
@@ -828,6 +857,9 @@ export const identityUaServiceFactory = ({
|
|||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
const identityUa = await identityUaDAL.findOne({ identityId });
|
const identityUa = await identityUaDAL.findOne({ identityId });
|
||||||
if (!identityUa) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!identityUa) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
@@ -835,22 +867,24 @@ export const identityUaServiceFactory = ({
|
|||||||
const clientSecret = await identityUaClientSecretDAL.findOne({ id: clientSecretId, identityUAId: identityUa.id });
|
const clientSecret = await identityUaClientSecretDAL.findOne({ id: clientSecretId, identityUAId: identityUa.id });
|
||||||
if (!clientSecret) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
if (!clientSecret) throw new NotFoundError({ message: `Failed to find identity with ID ${identityId}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Delete, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Delete, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { permission: rolePermission } = await permissionService.getOrgPermission(
|
const { permission: rolePermission } = await permissionService.getOrgPermission({
|
||||||
ActorType.IDENTITY,
|
actor: ActorType.IDENTITY,
|
||||||
identityMembershipOrg.identity.id,
|
actorId: identityMembershipOrg.identity.id,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(identityMembershipOrg.scopeOrgId);
|
||||||
const permissionBoundary = validatePrivilegeChangeOperation(
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
@@ -900,14 +934,18 @@ export const identityUaServiceFactory = ({
|
|||||||
message: "The identity does not have universal auth"
|
message: "The identity does not have universal auth"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (identityMembershipOrg.identity.identityOrgId !== actorOrgId) {
|
||||||
|
throw new ForbiddenRequestError({ message: "Sub organization not authorized to access this identity" });
|
||||||
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityMembershipOrg.scopeOrgId,
|
orgId: identityMembershipOrg.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const deleted = await keyStore.deleteItems({
|
const deleted = await keyStore.deleteItems({
|
||||||
|
|||||||
@@ -163,7 +163,8 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
.select(
|
.select(
|
||||||
selectAllTableCols(TableName.Membership),
|
selectAllTableCols(TableName.Membership),
|
||||||
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
||||||
db.ref("hasDeleteProtection").withSchema(TableName.Identity)
|
db.ref("hasDeleteProtection").withSchema(TableName.Identity),
|
||||||
|
db.ref("orgId").withSchema(TableName.Identity)
|
||||||
)
|
)
|
||||||
.where(filter)
|
.where(filter)
|
||||||
.as("paginatedIdentity");
|
.as("paginatedIdentity");
|
||||||
@@ -257,6 +258,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"),
|
db.ref("customRoleId").withSchema(TableName.MembershipRole).as("roleId"),
|
||||||
db.ref("scopeOrgId").withSchema("paginatedIdentity").as("orgId"),
|
db.ref("scopeOrgId").withSchema("paginatedIdentity").as("orgId"),
|
||||||
db.ref("lastLoginAuthMethod").withSchema("paginatedIdentity"),
|
db.ref("lastLoginAuthMethod").withSchema("paginatedIdentity"),
|
||||||
|
db.ref("orgId").withSchema("paginatedIdentity").as("identityOrgId"),
|
||||||
db.ref("lastLoginTime").withSchema("paginatedIdentity"),
|
db.ref("lastLoginTime").withSchema("paginatedIdentity"),
|
||||||
db.ref("createdAt").withSchema("paginatedIdentity"),
|
db.ref("createdAt").withSchema("paginatedIdentity"),
|
||||||
db.ref("updatedAt").withSchema("paginatedIdentity"),
|
db.ref("updatedAt").withSchema("paginatedIdentity"),
|
||||||
@@ -309,6 +311,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
roleId,
|
roleId,
|
||||||
id,
|
id,
|
||||||
orgId,
|
orgId,
|
||||||
|
identityOrgId,
|
||||||
uaId,
|
uaId,
|
||||||
alicloudId,
|
alicloudId,
|
||||||
awsId,
|
awsId,
|
||||||
@@ -348,6 +351,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
id: identityId as string,
|
id: identityId as string,
|
||||||
name: identityName,
|
name: identityName,
|
||||||
hasDeleteProtection,
|
hasDeleteProtection,
|
||||||
|
orgId: identityOrgId,
|
||||||
authMethods: buildAuthMethods({
|
authMethods: buildAuthMethods({
|
||||||
uaId,
|
uaId,
|
||||||
alicloudId,
|
alicloudId,
|
||||||
@@ -515,6 +519,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
db.ref("actorIdentityId").withSchema(TableName.Membership).as("identityId"),
|
db.ref("actorIdentityId").withSchema(TableName.Membership).as("identityId"),
|
||||||
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
||||||
db.ref("hasDeleteProtection").withSchema(TableName.Identity),
|
db.ref("hasDeleteProtection").withSchema(TableName.Identity),
|
||||||
|
db.ref("orgId").withSchema(TableName.Identity).as("identityOrgId"),
|
||||||
|
|
||||||
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
|
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
|
||||||
db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth),
|
db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth),
|
||||||
@@ -566,6 +571,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
crPermission,
|
crPermission,
|
||||||
crName,
|
crName,
|
||||||
identityId,
|
identityId,
|
||||||
|
identityOrgId,
|
||||||
identityName,
|
identityName,
|
||||||
hasDeleteProtection,
|
hasDeleteProtection,
|
||||||
role,
|
role,
|
||||||
@@ -611,6 +617,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
|
|||||||
id: identityId as string,
|
id: identityId as string,
|
||||||
name: identityName,
|
name: identityName,
|
||||||
hasDeleteProtection,
|
hasDeleteProtection,
|
||||||
|
orgId: identityOrgId,
|
||||||
authMethods: buildAuthMethods({
|
authMethods: buildAuthMethods({
|
||||||
uaId,
|
uaId,
|
||||||
alicloudId,
|
alicloudId,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope, OrgMembershipRole, TableName, TRoles } from "@app/db/schemas";
|
import { AccessScope, OrganizationActionScope, OrgMembershipRole, TableName, TRoles } from "@app/db/schemas";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
@@ -12,6 +12,7 @@ import { TKeyStoreFactory } from "@app/keystore/keystore";
|
|||||||
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
|
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
|
||||||
import { TIdentityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
|
import { TIdentityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
|
||||||
|
|
||||||
|
import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal";
|
||||||
import { TMembershipRoleDALFactory } from "../membership/membership-role-dal";
|
import { TMembershipRoleDALFactory } from "../membership/membership-role-dal";
|
||||||
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
|
||||||
import { TOrgDALFactory } from "../org/org-dal";
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
@@ -40,6 +41,7 @@ type TIdentityServiceFactoryDep = {
|
|||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan" | "updateSubscriptionOrgMemberCount">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan" | "updateSubscriptionOrgMemberCount">;
|
||||||
keyStore: Pick<TKeyStoreFactory, "getKeysByPattern" | "getItem">;
|
keyStore: Pick<TKeyStoreFactory, "getKeysByPattern" | "getItem">;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||||
|
additionalPrivilegeDAL: Pick<TAdditionalPrivilegeDALFactory, "delete">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TIdentityServiceFactory = ReturnType<typeof identityServiceFactory>;
|
export type TIdentityServiceFactory = ReturnType<typeof identityServiceFactory>;
|
||||||
@@ -54,7 +56,8 @@ export const identityServiceFactory = ({
|
|||||||
keyStore,
|
keyStore,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
membershipRoleDAL
|
membershipRoleDAL,
|
||||||
|
additionalPrivilegeDAL
|
||||||
}: TIdentityServiceFactoryDep) => {
|
}: TIdentityServiceFactoryDep) => {
|
||||||
const createIdentity = async ({
|
const createIdentity = async ({
|
||||||
name,
|
name,
|
||||||
@@ -67,7 +70,14 @@ export const identityServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
metadata
|
metadata
|
||||||
}: TCreateIdentityDTO) => {
|
}: TCreateIdentityDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const [rolePermissionDetails] = await permissionService.getOrgPermissionByRoles([role], orgId);
|
const [rolePermissionDetails] = await permissionService.getOrgPermissionByRoles([role], orgId);
|
||||||
@@ -104,7 +114,7 @@ export const identityServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const identity = await identityDAL.transaction(async (tx) => {
|
const identity = await identityDAL.transaction(async (tx) => {
|
||||||
const newIdentity = await identityDAL.create({ name, hasDeleteProtection }, tx);
|
const newIdentity = await identityDAL.create({ name, hasDeleteProtection, orgId }, tx);
|
||||||
const membership = await membershipIdentityDAL.create(
|
const membership = await membershipIdentityDAL.create(
|
||||||
{
|
{
|
||||||
scope: AccessScope.Organization,
|
scope: AccessScope.Organization,
|
||||||
@@ -172,13 +182,14 @@ export const identityServiceFactory = ({
|
|||||||
});
|
});
|
||||||
if (!identityOrgMembership) throw new NotFoundError({ message: `Failed to find identity with id ${id}` });
|
if (!identityOrgMembership) throw new NotFoundError({ message: `Failed to find identity with id ${id}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityOrgMembership.scopeOrgId,
|
orgId: identityOrgMembership.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
let customRole: TRoles | undefined;
|
let customRole: TRoles | undefined;
|
||||||
@@ -208,11 +219,12 @@ export const identityServiceFactory = ({
|
|||||||
if (isCustomRole) customRole = rolePermissionDetails?.role;
|
if (isCustomRole) customRole = rolePermissionDetails?.role;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const identityDetails = await identityDAL.findById(id);
|
||||||
const identity = await identityDAL.transaction(async (tx) => {
|
const identity = await identityDAL.transaction(async (tx) => {
|
||||||
const newIdentity =
|
const newIdentity =
|
||||||
name || hasDeleteProtection
|
identityDetails.orgId === actorOrgId && (name || hasDeleteProtection)
|
||||||
? await identityDAL.updateById(id, { name, hasDeleteProtection }, tx)
|
? await identityDAL.updateById(id, { name, hasDeleteProtection }, tx)
|
||||||
: await identityDAL.findById(id, tx);
|
: identityDetails;
|
||||||
|
|
||||||
if (role) {
|
if (role) {
|
||||||
await membershipRoleDAL.delete({ membershipId: identityOrgMembership.id }, tx);
|
await membershipRoleDAL.delete({ membershipId: identityOrgMembership.id }, tx);
|
||||||
@@ -264,16 +276,16 @@ export const identityServiceFactory = ({
|
|||||||
const identity = doc[0];
|
const identity = doc[0];
|
||||||
if (!identity) throw new NotFoundError({ message: `Failed to find identity with id ${id}` });
|
if (!identity) throw new NotFoundError({ message: `Failed to find identity with id ${id}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identity.orgId,
|
orgId: identity.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
// TODO(namespace): check this in identity service
|
|
||||||
const activeLockouts = await keyStore.getKeysByPattern(`lockout:identity:${id}:*`);
|
const activeLockouts = await keyStore.getKeysByPattern(`lockout:identity:${id}:*`);
|
||||||
|
|
||||||
const activeLockoutAuthMethods = new Set<string>();
|
const activeLockoutAuthMethods = new Set<string>();
|
||||||
@@ -314,23 +326,56 @@ export const identityServiceFactory = ({
|
|||||||
});
|
});
|
||||||
if (!identityOrgMembership) throw new NotFoundError({ message: `Failed to find identity with id ${id}` });
|
if (!identityOrgMembership) throw new NotFoundError({ message: `Failed to find identity with id ${id}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityOrgMembership.scopeOrgId,
|
orgId: identityOrgMembership.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Delete, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Delete, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
if (identityOrgMembership.identity.hasDeleteProtection)
|
if (identityOrgMembership.identity.hasDeleteProtection)
|
||||||
throw new BadRequestError({ message: "Identity has delete protection" });
|
throw new BadRequestError({ message: "Identity has delete protection" });
|
||||||
|
|
||||||
|
if (identityOrgMembership.identity.identityOrgId === actorOrgId) {
|
||||||
const deletedIdentity = await identityDAL.deleteById(id);
|
const deletedIdentity = await identityDAL.deleteById(id);
|
||||||
|
|
||||||
await licenseService.updateSubscriptionOrgMemberCount(identityOrgMembership.scopeOrgId);
|
await licenseService.updateSubscriptionOrgMemberCount(identityOrgMembership.scopeOrgId);
|
||||||
|
return { ...deletedIdentity, orgId: identityOrgMembership.scopeOrgId };
|
||||||
|
}
|
||||||
|
|
||||||
|
await membershipIdentityDAL.transaction(async (tx) => {
|
||||||
|
await identityMetadataDAL.delete(
|
||||||
|
{
|
||||||
|
identityId: id,
|
||||||
|
orgId: actorOrgId
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
const identityProjectMembership = await membershipIdentityDAL.find(
|
||||||
|
{
|
||||||
|
actorIdentityId: id,
|
||||||
|
scope: AccessScope.Project,
|
||||||
|
scopeOrgId: actorOrgId
|
||||||
|
},
|
||||||
|
{ tx }
|
||||||
|
);
|
||||||
|
await additionalPrivilegeDAL.delete(
|
||||||
|
{
|
||||||
|
actorIdentityId: id,
|
||||||
|
$in: {
|
||||||
|
projectId: identityProjectMembership.map((el) => el.scopeProjectId)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tx
|
||||||
|
);
|
||||||
|
const doc = await membershipIdentityDAL.delete({ actorIdentityId: id, scopeOrgId: actorOrgId }, tx);
|
||||||
|
return doc;
|
||||||
|
});
|
||||||
|
|
||||||
|
const deletedIdentity = await identityDAL.findById(id);
|
||||||
return { ...deletedIdentity, orgId: identityOrgMembership.scopeOrgId };
|
return { ...deletedIdentity, orgId: identityOrgMembership.scopeOrgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -346,7 +391,14 @@ export const identityServiceFactory = ({
|
|||||||
orderDirection,
|
orderDirection,
|
||||||
search
|
search
|
||||||
}: TListOrgIdentitiesByOrgIdDTO) => {
|
}: TListOrgIdentitiesByOrgIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const identityMemberships = await identityOrgMembershipDAL.find({
|
const identityMemberships = await identityOrgMembershipDAL.find({
|
||||||
@@ -379,7 +431,14 @@ export const identityServiceFactory = ({
|
|||||||
orderDirection,
|
orderDirection,
|
||||||
searchFilter = {}
|
searchFilter = {}
|
||||||
}: TSearchOrgIdentitiesByOrgIdDTO) => {
|
}: TSearchOrgIdentitiesByOrgIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
|
actor,
|
||||||
|
actorId,
|
||||||
|
orgId: actorOrgId,
|
||||||
|
actorAuthMethod,
|
||||||
|
actorOrgId
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const { totalCount, docs } = await identityOrgMembershipDAL.searchIdentities({
|
const { totalCount, docs } = await identityOrgMembershipDAL.searchIdentities({
|
||||||
@@ -408,16 +467,17 @@ export const identityServiceFactory = ({
|
|||||||
});
|
});
|
||||||
if (!identityOrgMembership) throw new NotFoundError({ message: `Failed to find identity with id ${identityId}` });
|
if (!identityOrgMembership) throw new NotFoundError({ message: `Failed to find identity with id ${identityId}` });
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
scope: OrganizationActionScope.Any,
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
identityOrgMembership.scopeOrgId,
|
orgId: identityOrgMembership.scopeOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId
|
||||||
);
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
const identityMemberships = await identityProjectDAL.findByIdentityId(identityId);
|
const identityMemberships = await identityProjectDAL.findByIdentityId(identityId, actorOrgId);
|
||||||
return identityMemberships;
|
return identityMemberships;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -112,7 +112,7 @@ export const integrationAuthServiceFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const listOrgIntegrationAuth = async ({ actorId, actor, actorOrgId, actorAuthMethod }: TGenericPermission) => {
|
const listOrgIntegrationAuth = async ({ actorId, actor, actorOrgId, actorAuthMethod }: TGenericPermission) => {
|
||||||
const authorizations = await integrationAuthDAL.getByOrg(actorOrgId as string);
|
const authorizations = await integrationAuthDAL.getByOrg(actorOrgId);
|
||||||
|
|
||||||
const filteredAuthorizations = await Promise.all(
|
const filteredAuthorizations = await Promise.all(
|
||||||
authorizations.map(async (auth) => {
|
authorizations.map(async (auth) => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope, OrgMembershipRole } from "@app/db/schemas";
|
import { AccessScope, OrganizationActionScope, OrgMembershipRole } from "@app/db/schemas";
|
||||||
import { OrgPermissionGroupActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionGroupActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
constructPermissionErrorMessage,
|
constructPermissionErrorMessage,
|
||||||
@@ -45,13 +45,14 @@ export const newOrgMembershipGroupFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onUpdateMembershipGroupGuard: TMembershipGroupScopeFactory["onUpdateMembershipGroupGuard"] = async (dto) => {
|
const onUpdateMembershipGroupGuard: TMembershipGroupScopeFactory["onUpdateMembershipGroupGuard"] = async (dto) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Edit, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Edit, OrgPermissionSubjects.Groups);
|
||||||
const permissionRoles = await permissionService.getOrgPermissionByRoles(
|
const permissionRoles = await permissionService.getOrgPermissionByRoles(
|
||||||
dto.data.roles.map((el) => el.role),
|
dto.data.roles.map((el) => el.role),
|
||||||
@@ -89,26 +90,28 @@ export const newOrgMembershipGroupFactory = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onListMembershipGroupGuard: TMembershipGroupScopeFactory["onListMembershipGroupGuard"] = async (dto) => {
|
const onListMembershipGroupGuard: TMembershipGroupScopeFactory["onListMembershipGroupGuard"] = async (dto) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Read, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Read, OrgPermissionSubjects.Groups);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onGetMembershipGroupByGroupIdGuard: TMembershipGroupScopeFactory["onGetMembershipGroupByGroupIdGuard"] = async (
|
const onGetMembershipGroupByGroupIdGuard: TMembershipGroupScopeFactory["onGetMembershipGroupByGroupIdGuard"] = async (
|
||||||
dto
|
dto
|
||||||
) => {
|
) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Read, OrgPermissionSubjects.Groups);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionGroupActions.Read, OrgPermissionSubjects.Groups);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -91,6 +91,7 @@ export const membershipIdentityDALFactory = (db: TDbClient) => {
|
|||||||
.select(
|
.select(
|
||||||
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
db.ref("name").withSchema(TableName.Identity).as("identityName"),
|
||||||
db.ref("id").withSchema(TableName.Identity).as("identityId"),
|
db.ref("id").withSchema(TableName.Identity).as("identityId"),
|
||||||
|
db.ref("orgId").withSchema(TableName.Identity).as("identityOrgId"),
|
||||||
db.ref("hasDeleteProtection").withSchema(TableName.Identity).as("identityHasDeleteProtection"),
|
db.ref("hasDeleteProtection").withSchema(TableName.Identity).as("identityHasDeleteProtection"),
|
||||||
|
|
||||||
db.ref("slug").withSchema(TableName.Role).as("roleSlug"),
|
db.ref("slug").withSchema(TableName.Role).as("roleSlug"),
|
||||||
@@ -132,6 +133,7 @@ export const membershipIdentityDALFactory = (db: TDbClient) => {
|
|||||||
parentMapper: (el) => {
|
parentMapper: (el) => {
|
||||||
const {
|
const {
|
||||||
identityId: actorIdentityId,
|
identityId: actorIdentityId,
|
||||||
|
identityOrgId,
|
||||||
identityHasDeleteProtection,
|
identityHasDeleteProtection,
|
||||||
identityName,
|
identityName,
|
||||||
uaId,
|
uaId,
|
||||||
@@ -153,6 +155,7 @@ export const membershipIdentityDALFactory = (db: TDbClient) => {
|
|||||||
name: identityName,
|
name: identityName,
|
||||||
id: actorIdentityId,
|
id: actorIdentityId,
|
||||||
hasDeleteProtection: identityHasDeleteProtection,
|
hasDeleteProtection: identityHasDeleteProtection,
|
||||||
|
identityOrgId,
|
||||||
authMethods: buildAuthMethods({
|
authMethods: buildAuthMethods({
|
||||||
uaId,
|
uaId,
|
||||||
awsId,
|
awsId,
|
||||||
@@ -353,5 +356,34 @@ export const membershipIdentityDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...orm, findIdentities, getIdentityById };
|
// this right now only support sub organization
|
||||||
|
const listAvailableIdentities = async (orgId: string, rootOrgId: string) => {
|
||||||
|
try {
|
||||||
|
const usersConnectedToOrg = db
|
||||||
|
.replicaNode()(TableName.Membership)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
|
.select("actorIdentityId");
|
||||||
|
|
||||||
|
const docs = await db
|
||||||
|
.replicaNode()(TableName.Membership)
|
||||||
|
.join(TableName.Identity, `${TableName.Identity}.id`, `${TableName.Membership}.actorIdentityId`)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
|
.where(`${TableName.Membership}.scopeOrgId`, rootOrgId)
|
||||||
|
.whereNotIn(`${TableName.Membership}.actorIdentityId`, usersConnectedToOrg)
|
||||||
|
.select(
|
||||||
|
db.ref("id").withSchema(TableName.Identity),
|
||||||
|
db.ref("name").withSchema(TableName.Identity),
|
||||||
|
db.ref("hasDeleteProtection").withSchema(TableName.Identity)
|
||||||
|
);
|
||||||
|
|
||||||
|
return docs;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "ListAvailableIdentities" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { ...orm, findIdentities, getIdentityById, listAvailableIdentities };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { ms } from "@app/lib/ms";
|
|||||||
import { SearchResourceOperators } from "@app/lib/search-resource/search";
|
import { SearchResourceOperators } from "@app/lib/search-resource/search";
|
||||||
|
|
||||||
import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal";
|
import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal";
|
||||||
|
import { TIdentityDALFactory } from "../identity/identity-dal";
|
||||||
import { TMembershipRoleDALFactory } from "../membership/membership-role-dal";
|
import { TMembershipRoleDALFactory } from "../membership/membership-role-dal";
|
||||||
import { TOrgDALFactory } from "../org/org-dal";
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
import { TRoleDALFactory } from "../role/role-dal";
|
import { TRoleDALFactory } from "../role/role-dal";
|
||||||
@@ -31,6 +32,7 @@ type TMembershipIdentityServiceFactoryDep = {
|
|||||||
>;
|
>;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||||
additionalPrivilegeDAL: Pick<TAdditionalPrivilegeDALFactory, "delete">;
|
additionalPrivilegeDAL: Pick<TAdditionalPrivilegeDALFactory, "delete">;
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TMembershipIdentityServiceFactory = ReturnType<typeof membershipIdentityServiceFactory>;
|
export type TMembershipIdentityServiceFactory = ReturnType<typeof membershipIdentityServiceFactory>;
|
||||||
@@ -41,12 +43,14 @@ export const membershipIdentityServiceFactory = ({
|
|||||||
membershipRoleDAL,
|
membershipRoleDAL,
|
||||||
permissionService,
|
permissionService,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
additionalPrivilegeDAL
|
additionalPrivilegeDAL,
|
||||||
|
identityDAL
|
||||||
}: TMembershipIdentityServiceFactoryDep) => {
|
}: TMembershipIdentityServiceFactoryDep) => {
|
||||||
const scopeFactory = {
|
const scopeFactory = {
|
||||||
[AccessScope.Organization]: newOrgMembershipIdentityFactory({
|
[AccessScope.Organization]: newOrgMembershipIdentityFactory({
|
||||||
orgDAL,
|
orgDAL,
|
||||||
permissionService
|
permissionService,
|
||||||
|
identityDAL
|
||||||
}),
|
}),
|
||||||
[AccessScope.Project]: newProjectMembershipIdentityFactory({
|
[AccessScope.Project]: newProjectMembershipIdentityFactory({
|
||||||
membershipIdentityDAL,
|
membershipIdentityDAL,
|
||||||
@@ -305,7 +309,7 @@ export const membershipIdentityServiceFactory = ({
|
|||||||
[SearchResourceOperators.$contains]: dto.data.identityName
|
[SearchResourceOperators.$contains]: dto.data.identityName
|
||||||
}
|
}
|
||||||
: undefined,
|
: undefined,
|
||||||
role: dto.data.roles.length
|
role: dto.data?.roles?.length
|
||||||
? {
|
? {
|
||||||
[SearchResourceOperators.$in]: dto.data.roles
|
[SearchResourceOperators.$in]: dto.data.roles
|
||||||
}
|
}
|
||||||
@@ -329,11 +333,29 @@ export const membershipIdentityServiceFactory = ({
|
|||||||
return membership;
|
return membership;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const listAvailableIdentities = async (dto: TListMembershipIdentityDTO) => {
|
||||||
|
const { scopeData } = dto;
|
||||||
|
const factory = scopeFactory[scopeData.scope];
|
||||||
|
|
||||||
|
await factory.onListMembershipIdentityGuard(dto);
|
||||||
|
|
||||||
|
const organizationDetails = await orgDAL.findById(dto.scopeData.orgId);
|
||||||
|
if (!organizationDetails.rootOrgId) return { identities: [] };
|
||||||
|
|
||||||
|
const identities = await membershipIdentityDAL.listAvailableIdentities(
|
||||||
|
organizationDetails.id,
|
||||||
|
organizationDetails.rootOrgId
|
||||||
|
);
|
||||||
|
|
||||||
|
return { identities };
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createMembership,
|
createMembership,
|
||||||
updateMembership,
|
updateMembership,
|
||||||
deleteMembership,
|
deleteMembership,
|
||||||
listMemberships,
|
listMemberships,
|
||||||
getMembershipByIdentityId
|
getMembershipByIdentityId,
|
||||||
|
listAvailableIdentities
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -54,14 +54,11 @@ export type TUpdateMembershipIdentityDTO = {
|
|||||||
export type TListMembershipIdentityDTO = {
|
export type TListMembershipIdentityDTO = {
|
||||||
permission: OrgServiceActor;
|
permission: OrgServiceActor;
|
||||||
scopeData: AccessScopeData;
|
scopeData: AccessScopeData;
|
||||||
selector: {
|
|
||||||
identityId: string;
|
|
||||||
};
|
|
||||||
data: {
|
data: {
|
||||||
limit?: number;
|
limit?: number;
|
||||||
offset?: number;
|
offset?: number;
|
||||||
identityName?: string;
|
identityName?: string;
|
||||||
roles: string[];
|
roles?: string[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope, OrgMembershipRole } from "@app/db/schemas";
|
import { AccessScope, OrganizationActionScope, OrgMembershipRole } from "@app/db/schemas";
|
||||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import {
|
import {
|
||||||
constructPermissionErrorMessage,
|
constructPermissionErrorMessage,
|
||||||
@@ -8,6 +8,7 @@ import {
|
|||||||
} from "@app/ee/services/permission/permission-fns";
|
} from "@app/ee/services/permission/permission-fns";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { BadRequestError, InternalServerError, PermissionBoundaryError } from "@app/lib/errors";
|
import { BadRequestError, InternalServerError, PermissionBoundaryError } from "@app/lib/errors";
|
||||||
|
import { TIdentityDALFactory } from "@app/services/identity/identity-dal";
|
||||||
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
import { TOrgDALFactory } from "@app/services/org/org-dal";
|
||||||
import { isCustomOrgRole } from "@app/services/org/org-role-fns";
|
import { isCustomOrgRole } from "@app/services/org/org-role-fns";
|
||||||
|
|
||||||
@@ -16,11 +17,13 @@ import { TMembershipIdentityScopeFactory } from "../membership-identity-types";
|
|||||||
type TOrgMembershipIdentityScopeFactoryDep = {
|
type TOrgMembershipIdentityScopeFactoryDep = {
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getOrgPermissionByRoles">;
|
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getOrgPermissionByRoles">;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||||
|
identityDAL: Pick<TIdentityDALFactory, "findById">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const newOrgMembershipIdentityFactory = ({
|
export const newOrgMembershipIdentityFactory = ({
|
||||||
permissionService,
|
permissionService,
|
||||||
orgDAL
|
orgDAL,
|
||||||
|
identityDAL
|
||||||
}: TOrgMembershipIdentityScopeFactoryDep): TMembershipIdentityScopeFactory => {
|
}: TOrgMembershipIdentityScopeFactoryDep): TMembershipIdentityScopeFactory => {
|
||||||
const getScopeField: TMembershipIdentityScopeFactory["getScopeField"] = (dto) => {
|
const getScopeField: TMembershipIdentityScopeFactory["getScopeField"] = (dto) => {
|
||||||
if (dto.scope === AccessScope.Organization) {
|
if (dto.scope === AccessScope.Organization) {
|
||||||
@@ -38,23 +41,66 @@ export const newOrgMembershipIdentityFactory = ({
|
|||||||
|
|
||||||
const isCustomRole: TMembershipIdentityScopeFactory["isCustomRole"] = (role: string) => isCustomOrgRole(role);
|
const isCustomRole: TMembershipIdentityScopeFactory["isCustomRole"] = (role: string) => isCustomOrgRole(role);
|
||||||
|
|
||||||
const onCreateMembershipIdentityGuard: TMembershipIdentityScopeFactory["onCreateMembershipIdentityGuard"] =
|
const onCreateMembershipIdentityGuard: TMembershipIdentityScopeFactory["onCreateMembershipIdentityGuard"] = async (
|
||||||
async () => {
|
dto
|
||||||
throw new BadRequestError({
|
) => {
|
||||||
message: "Organization membership cannot be created for organization scoped identity"
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actor: dto.permission.type,
|
||||||
|
actorId: dto.permission.id,
|
||||||
|
orgId: dto.permission.orgId,
|
||||||
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
|
actorOrgId: dto.permission.orgId,
|
||||||
|
scope: OrganizationActionScope.ChildOrganization
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
|
const identityDetails = await identityDAL.findById(dto.data.identityId);
|
||||||
|
if (identityDetails.orgId !== dto.permission.rootOrgId) {
|
||||||
|
throw new BadRequestError({ message: "Only identities from parent organization can be invited" });
|
||||||
|
}
|
||||||
|
|
||||||
|
const permissionRoles = await permissionService.getOrgPermissionByRoles(
|
||||||
|
dto.data.roles.map((el) => el.role),
|
||||||
|
dto.permission.orgId
|
||||||
|
);
|
||||||
|
|
||||||
|
const { shouldUseNewPrivilegeSystem } = await orgDAL.findById(dto.permission.orgId);
|
||||||
|
for (const permissionRole of permissionRoles) {
|
||||||
|
if (permissionRole?.role?.name !== OrgMembershipRole.NoAccess) {
|
||||||
|
const permissionBoundary = validatePrivilegeChangeOperation(
|
||||||
|
shouldUseNewPrivilegeSystem,
|
||||||
|
OrgPermissionIdentityActions.GrantPrivileges,
|
||||||
|
OrgPermissionSubjects.Identity,
|
||||||
|
permission,
|
||||||
|
permissionRole.permission
|
||||||
|
);
|
||||||
|
if (!permissionBoundary.isValid)
|
||||||
|
throw new PermissionBoundaryError({
|
||||||
|
message: constructPermissionErrorMessage(
|
||||||
|
"Failed to update identity org membership",
|
||||||
|
shouldUseNewPrivilegeSystem,
|
||||||
|
OrgPermissionIdentityActions.GrantPrivileges,
|
||||||
|
OrgPermissionSubjects.Identity
|
||||||
|
),
|
||||||
|
details: { missingPermissions: permissionBoundary.missingPermissions }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onUpdateMembershipIdentityGuard: TMembershipIdentityScopeFactory["onUpdateMembershipIdentityGuard"] = async (
|
const onUpdateMembershipIdentityGuard: TMembershipIdentityScopeFactory["onUpdateMembershipIdentityGuard"] = async (
|
||||||
dto
|
dto
|
||||||
) => {
|
) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||||
const permissionRoles = await permissionService.getOrgPermissionByRoles(
|
const permissionRoles = await permissionService.getOrgPermissionByRoles(
|
||||||
dto.data.roles.map((el) => el.role),
|
dto.data.roles.map((el) => el.role),
|
||||||
@@ -85,35 +131,54 @@ export const newOrgMembershipIdentityFactory = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDeleteMembershipIdentityGuard: TMembershipIdentityScopeFactory["onDeleteMembershipIdentityGuard"] =
|
const onDeleteMembershipIdentityGuard: TMembershipIdentityScopeFactory["onDeleteMembershipIdentityGuard"] = async (
|
||||||
async () => {
|
dto
|
||||||
throw new BadRequestError({
|
) => {
|
||||||
message: "Organization membership cannot be deleted for organization scoped identity"
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
|
actor: dto.permission.type,
|
||||||
|
actorId: dto.permission.id,
|
||||||
|
orgId: dto.permission.orgId,
|
||||||
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
|
actorOrgId: dto.permission.orgId,
|
||||||
|
scope: OrganizationActionScope.ChildOrganization
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Delete, OrgPermissionSubjects.Identity);
|
||||||
|
|
||||||
|
const identityDetails = await identityDAL.findById(dto.selector.identityId);
|
||||||
|
if (identityDetails.orgId !== dto.permission.rootOrgId) {
|
||||||
|
throw new BadRequestError({ message: "Only identities from parent organization can do this operation" });
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identityDetails.orgId === dto.permission.orgId) {
|
||||||
|
throw new BadRequestError({ message: "Identity cannot exist as orphan" });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onListMembershipIdentityGuard: TMembershipIdentityScopeFactory["onListMembershipIdentityGuard"] = async (
|
const onListMembershipIdentityGuard: TMembershipIdentityScopeFactory["onListMembershipIdentityGuard"] = async (
|
||||||
dto
|
dto
|
||||||
) => {
|
) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onGetMembershipIdentityByIdentityIdGuard: TMembershipIdentityScopeFactory["onGetMembershipIdentityByIdentityIdGuard"] =
|
const onGetMembershipIdentityByIdentityIdGuard: TMembershipIdentityScopeFactory["onGetMembershipIdentityByIdentityIdGuard"] =
|
||||||
async (dto) => {
|
async (dto) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Read, OrgPermissionSubjects.Identity);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -291,5 +291,37 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return { ...orm, findUsers, getUserById };
|
// this right now only support sub organization
|
||||||
|
const listAvailableUsers = async (orgId: string, rootOrgId: string) => {
|
||||||
|
try {
|
||||||
|
const usersConnectedToOrg = db
|
||||||
|
.replicaNode()(TableName.Membership)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.where(`${TableName.Membership}.scopeOrgId`, orgId)
|
||||||
|
.select("actorUserId");
|
||||||
|
|
||||||
|
const docs = await db
|
||||||
|
.replicaNode()(TableName.Membership)
|
||||||
|
.join(TableName.Users, `${TableName.Users}.id`, `${TableName.Membership}.actorUserId`)
|
||||||
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
|
.where(`${TableName.Users}.isGhost`, false)
|
||||||
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
|
.where(`${TableName.Membership}.scopeOrgId`, rootOrgId)
|
||||||
|
.whereNotIn(`${TableName.Membership}.actorUserId`, usersConnectedToOrg)
|
||||||
|
.select(
|
||||||
|
db.ref("id").withSchema(TableName.Users),
|
||||||
|
db.ref("email").withSchema(TableName.Users),
|
||||||
|
db.ref("username").withSchema(TableName.Users),
|
||||||
|
db.ref("firstName").withSchema(TableName.Users),
|
||||||
|
db.ref("lastName").withSchema(TableName.Users)
|
||||||
|
);
|
||||||
|
|
||||||
|
return docs;
|
||||||
|
} catch (error) {
|
||||||
|
throw new DatabaseError({ error, name: "ListAvailableUsers" });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return { ...orm, findUsers, getUserById, listAvailableUsers };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ import { newProjectMembershipUserFactory } from "./project/project-membership-us
|
|||||||
type TMembershipUserServiceFactoryDep = {
|
type TMembershipUserServiceFactoryDep = {
|
||||||
membershipUserDAL: TMembershipUserDALFactory;
|
membershipUserDAL: TMembershipUserDALFactory;
|
||||||
membershipRoleDAL: Pick<TMembershipRoleDALFactory, "insertMany" | "delete">;
|
membershipRoleDAL: Pick<TMembershipRoleDALFactory, "insertMany" | "delete">;
|
||||||
orgDAL: Pick<TOrgDALFactory, "findById" | "transaction">;
|
orgDAL: Pick<TOrgDALFactory, "findById" | "transaction" | "find">;
|
||||||
roleDAL: Pick<TRoleDALFactory, "find">;
|
roleDAL: Pick<TRoleDALFactory, "find">;
|
||||||
userDAL: TUserDALFactory;
|
userDAL: TUserDALFactory;
|
||||||
permissionService: Pick<
|
permissionService: Pick<
|
||||||
@@ -83,7 +83,8 @@ export const membershipUserServiceFactory = ({
|
|||||||
orgDAL,
|
orgDAL,
|
||||||
tokenService,
|
tokenService,
|
||||||
userDAL,
|
userDAL,
|
||||||
userGroupMembershipDAL
|
userGroupMembershipDAL,
|
||||||
|
membershipUserDAL
|
||||||
}),
|
}),
|
||||||
[AccessScope.Namespace]: newNamespaceMembershipUserFactory({}),
|
[AccessScope.Namespace]: newNamespaceMembershipUserFactory({}),
|
||||||
[AccessScope.Project]: newProjectMembershipUserFactory({
|
[AccessScope.Project]: newProjectMembershipUserFactory({
|
||||||
@@ -404,7 +405,7 @@ export const membershipUserServiceFactory = ({
|
|||||||
const membershipDoc = await membershipUserDAL.transaction(async (tx) => {
|
const membershipDoc = await membershipUserDAL.transaction(async (tx) => {
|
||||||
if (dto.scopeData.scope === AccessScope.Organization) {
|
if (dto.scopeData.scope === AccessScope.Organization) {
|
||||||
const [doc] = await deleteOrgMembershipsFn({
|
const [doc] = await deleteOrgMembershipsFn({
|
||||||
orgMembershipIds: [],
|
orgMembershipIds: [existingMembership.id],
|
||||||
orgId: dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
projectKeyDAL,
|
projectKeyDAL,
|
||||||
@@ -471,11 +472,26 @@ export const membershipUserServiceFactory = ({
|
|||||||
return membership;
|
return membership;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Should only be used for sub organization as of now
|
||||||
|
const listAvailableUsers = async (dto: TListMembershipUserDTO) => {
|
||||||
|
const { scopeData } = dto;
|
||||||
|
const factory = scopeFactory[scopeData.scope];
|
||||||
|
|
||||||
|
await factory.onListMembershipUserGuard(dto);
|
||||||
|
|
||||||
|
const organizationDetails = await orgDAL.findById(dto.scopeData.orgId);
|
||||||
|
if (!organizationDetails.rootOrgId) return { users: [] };
|
||||||
|
|
||||||
|
const users = await membershipUserDAL.listAvailableUsers(organizationDetails.id, organizationDetails.rootOrgId);
|
||||||
|
return { users };
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createMembership,
|
createMembership,
|
||||||
updateMembership,
|
updateMembership,
|
||||||
deleteMembership,
|
deleteMembership,
|
||||||
listMemberships,
|
listMemberships,
|
||||||
getMembershipByUserId
|
getMembershipByUserId,
|
||||||
|
listAvailableUsers
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -93,3 +93,8 @@ export type TGetMembershipUserByUserIdDTO = {
|
|||||||
userId: string;
|
userId: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TListAvailableUsersDTO = {
|
||||||
|
permission: OrgServiceActor;
|
||||||
|
scopeData: AccessScopeData;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ForbiddenError } from "@casl/ability";
|
import { ForbiddenError } from "@casl/ability";
|
||||||
|
|
||||||
import { AccessScope } from "@app/db/schemas";
|
import { AccessScope, OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
import { TUserGroupMembershipDALFactory } from "@app/ee/services/group/user-group-membership-dal";
|
||||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
@@ -15,6 +15,7 @@ import { isCustomOrgRole } from "@app/services/org/org-role-fns";
|
|||||||
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
|
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
|
||||||
import { TUserDALFactory } from "@app/services/user/user-dal";
|
import { TUserDALFactory } from "@app/services/user/user-dal";
|
||||||
|
|
||||||
|
import { TMembershipUserDALFactory } from "../membership-user-dal";
|
||||||
import { TMembershipUserScopeFactory } from "../membership-user-types";
|
import { TMembershipUserScopeFactory } from "../membership-user-types";
|
||||||
|
|
||||||
type TOrgMembershipUserScopeFactoryDep = {
|
type TOrgMembershipUserScopeFactoryDep = {
|
||||||
@@ -25,6 +26,7 @@ type TOrgMembershipUserScopeFactoryDep = {
|
|||||||
orgDAL: Pick<TOrgDALFactory, "findById">;
|
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||||
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "delete">;
|
userGroupMembershipDAL: Pick<TUserGroupMembershipDALFactory, "delete">;
|
||||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||||
|
membershipUserDAL: Pick<TMembershipUserDALFactory, "find">;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const newOrgMembershipUserFactory = ({
|
export const newOrgMembershipUserFactory = ({
|
||||||
@@ -33,7 +35,8 @@ export const newOrgMembershipUserFactory = ({
|
|||||||
userDAL,
|
userDAL,
|
||||||
orgDAL,
|
orgDAL,
|
||||||
smtpService,
|
smtpService,
|
||||||
licenseService
|
licenseService,
|
||||||
|
membershipUserDAL
|
||||||
}: TOrgMembershipUserScopeFactoryDep): TMembershipUserScopeFactory => {
|
}: TOrgMembershipUserScopeFactoryDep): TMembershipUserScopeFactory => {
|
||||||
const getScopeField: TMembershipUserScopeFactory["getScopeField"] = (dto) => {
|
const getScopeField: TMembershipUserScopeFactory["getScopeField"] = (dto) => {
|
||||||
if (dto.scope === AccessScope.Organization) {
|
if (dto.scope === AccessScope.Organization) {
|
||||||
@@ -51,14 +54,18 @@ export const newOrgMembershipUserFactory = ({
|
|||||||
|
|
||||||
const isCustomRole: TMembershipUserScopeFactory["isCustomRole"] = (role: string) => isCustomOrgRole(role);
|
const isCustomRole: TMembershipUserScopeFactory["isCustomRole"] = (role: string) => isCustomOrgRole(role);
|
||||||
|
|
||||||
const onCreateMembershipUserGuard: TMembershipUserScopeFactory["onCreateMembershipUserGuard"] = async (dto) => {
|
const onCreateMembershipUserGuard: TMembershipUserScopeFactory["onCreateMembershipUserGuard"] = async (
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
dto,
|
||||||
dto.permission.type,
|
newMembers
|
||||||
dto.permission.id,
|
) => {
|
||||||
dto.permission.orgId,
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.authMethod,
|
actor: dto.permission.type,
|
||||||
dto.permission.orgId
|
actorId: dto.permission.id,
|
||||||
);
|
orgId: dto.permission.orgId,
|
||||||
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
|
actorOrgId: dto.permission.orgId,
|
||||||
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Member);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Member);
|
||||||
|
|
||||||
const plan = await licenseService.getPlan(dto.permission.orgId);
|
const plan = await licenseService.getPlan(dto.permission.orgId);
|
||||||
@@ -77,6 +84,25 @@ export const newOrgMembershipUserFactory = ({
|
|||||||
message: "Failed to invite user due to org-level auth enforced for organization"
|
message: "Failed to invite user due to org-level auth enforced for organization"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (org.rootOrgId) {
|
||||||
|
const rootOrgMembership = await membershipUserDAL.find({
|
||||||
|
scope: AccessScope.Organization,
|
||||||
|
$in: {
|
||||||
|
actorUserId: newMembers.map((el) => el.id)
|
||||||
|
},
|
||||||
|
scopeOrgId: org.rootOrgId
|
||||||
|
});
|
||||||
|
if (rootOrgMembership.length !== newMembers.length) {
|
||||||
|
const emails = newMembers
|
||||||
|
.filter((user) => !rootOrgMembership.find((i) => i.actorUserId === user.id))
|
||||||
|
.map((el) => el.email)
|
||||||
|
.join(",");
|
||||||
|
throw new BadRequestError({
|
||||||
|
message: `Users with email ${emails} doesn't have membership in root organization`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const onCreateMembershipComplete: TMembershipUserScopeFactory["onCreateMembershipComplete"] = async (
|
const onCreateMembershipComplete: TMembershipUserScopeFactory["onCreateMembershipComplete"] = async (
|
||||||
@@ -95,7 +121,18 @@ export const newOrgMembershipUserFactory = ({
|
|||||||
|
|
||||||
const signUpTokens: { email: string; link: string }[] = [];
|
const signUpTokens: { email: string; link: string }[] = [];
|
||||||
const orgDetails = await orgDAL.findById(dto.permission.orgId);
|
const orgDetails = await orgDAL.findById(dto.permission.orgId);
|
||||||
|
if (orgDetails.rootOrgId) {
|
||||||
|
const emails = newUsers.map((el) => el.email).filter(Boolean);
|
||||||
|
await smtpService.sendMail({
|
||||||
|
template: SmtpTemplates.SubOrgInvite,
|
||||||
|
subjectLine: "Infisical sub-organization invitation",
|
||||||
|
recipients: emails as string[],
|
||||||
|
substitutions: {
|
||||||
|
subOrganizationName: orgDetails.slug,
|
||||||
|
callback_url: `${appCfg.SITE_URL}/organization/projects?subOrganization=${orgDetails.slug}`
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
await Promise.allSettled(
|
await Promise.allSettled(
|
||||||
newUsers.map(async (el) => {
|
newUsers.map(async (el) => {
|
||||||
const token = await tokenService.createTokenForUser({
|
const token = await tokenService.createTokenForUser({
|
||||||
@@ -129,53 +166,58 @@ export const newOrgMembershipUserFactory = ({
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return { signUpTokens };
|
return { signUpTokens };
|
||||||
};
|
};
|
||||||
|
|
||||||
const onUpdateMembershipUserGuard: TMembershipUserScopeFactory["onUpdateMembershipUserGuard"] = async (dto) => {
|
const onUpdateMembershipUserGuard: TMembershipUserScopeFactory["onUpdateMembershipUserGuard"] = async (dto) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Member);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Member);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onDeleteMembershipUserGuard: TMembershipUserScopeFactory["onDeleteMembershipUserGuard"] = async (dto) => {
|
const onDeleteMembershipUserGuard: TMembershipUserScopeFactory["onDeleteMembershipUserGuard"] = async (dto) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Member);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Member);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onListMembershipUserGuard: TMembershipUserScopeFactory["onListMembershipUserGuard"] = async (dto) => {
|
const onListMembershipUserGuard: TMembershipUserScopeFactory["onListMembershipUserGuard"] = async (dto) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onGetMembershipUserByUserIdGuard: TMembershipUserScopeFactory["onGetMembershipUserByUserIdGuard"] = async (
|
const onGetMembershipUserByUserIdGuard: TMembershipUserScopeFactory["onGetMembershipUserByUserIdGuard"] = async (
|
||||||
dto
|
dto
|
||||||
) => {
|
) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
dto.permission.type,
|
actor: dto.permission.type,
|
||||||
dto.permission.id,
|
actorId: dto.permission.id,
|
||||||
dto.permission.orgId,
|
orgId: dto.permission.orgId,
|
||||||
dto.permission.authMethod,
|
actorAuthMethod: dto.permission.authMethod,
|
||||||
dto.permission.orgId
|
actorOrgId: dto.permission.orgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Member);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
import { CronJob } from "cron";
|
import { CronJob } from "cron";
|
||||||
import { FastifyReply, FastifyRequest } from "fastify";
|
import { FastifyReply, FastifyRequest } from "fastify";
|
||||||
|
|
||||||
|
import { OrganizationActionScope } from "@app/db/schemas";
|
||||||
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
import { OrgPermissionActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||||
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
|
||||||
import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors";
|
import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors";
|
||||||
@@ -208,13 +209,14 @@ export const microsoftTeamsServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
microsoftTeamsIntegration.orgId,
|
orgId: microsoftTeamsIntegration.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -282,13 +284,14 @@ export const microsoftTeamsServiceFactory = ({
|
|||||||
description,
|
description,
|
||||||
redirectUri
|
redirectUri
|
||||||
}: TCreateMicrosoftTeamsIntegrationDTO) => {
|
}: TCreateMicrosoftTeamsIntegrationDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -393,13 +396,14 @@ export const microsoftTeamsServiceFactory = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
const getClientId = async ({ actorId, actor, actorOrgId, actorAuthMethod }: TGetClientIdDTO) => {
|
const getClientId = async ({ actorId, actor, actorOrgId, actorAuthMethod }: TGetClientIdDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -427,13 +431,14 @@ export const microsoftTeamsServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod
|
actorAuthMethod
|
||||||
}: TGetMicrosoftTeamsIntegrationByOrgDTO) => {
|
}: TGetMicrosoftTeamsIntegrationByOrgDTO) => {
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Create, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -463,13 +468,14 @@ export const microsoftTeamsServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
microsoftTeamsIntegration.orgId,
|
orgId: microsoftTeamsIntegration.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -495,13 +501,14 @@ export const microsoftTeamsServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
microsoftTeamsIntegration.orgId,
|
orgId: microsoftTeamsIntegration.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Edit, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -549,13 +556,14 @@ export const microsoftTeamsServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
microsoftTeamsIntegration.orgId,
|
orgId: microsoftTeamsIntegration.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Delete, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
@@ -577,13 +585,14 @@ export const microsoftTeamsServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const { permission } = await permissionService.getOrgPermission(
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
microsoftTeamsIntegration.orgId,
|
orgId: microsoftTeamsIntegration.orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId
|
actorOrgId,
|
||||||
);
|
scope: OrganizationActionScope.Any
|
||||||
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Settings);
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user