mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat: switched to root org id pattern
This commit is contained in:
1
backend/src/@types/fastify.d.ts
vendored
1
backend/src/@types/fastify.d.ts
vendored
@@ -180,6 +180,7 @@ declare module "fastify" {
|
|||||||
id: string;
|
id: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
parentOrgId: string;
|
parentOrgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
};
|
};
|
||||||
rateLimits: RateLimitConfiguration;
|
rateLimits: RateLimitConfiguration;
|
||||||
// passport data
|
// passport data
|
||||||
|
|||||||
@@ -6,8 +6,12 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
|
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
|
||||||
if (!hasParentOrgId) {
|
if (!hasParentOrgId) {
|
||||||
await knex.schema.alterTable(TableName.Organization, (t) => {
|
await knex.schema.alterTable(TableName.Organization, (t) => {
|
||||||
|
// the one just above the chain
|
||||||
t.uuid("parentOrgId");
|
t.uuid("parentOrgId");
|
||||||
t.foreign("parentOrgId").references("id").inTable(TableName.Organization).onDelete("CASCADE");
|
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");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,9 +26,11 @@ export async function up(knex: Knex): Promise<void> {
|
|||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
export async function down(knex: Knex): Promise<void> {
|
||||||
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
|
const hasParentOrgId = await knex.schema.hasColumn(TableName.Organization, "parentOrgId");
|
||||||
if (hasParentOrgId) {
|
const hasRootOrgId = await knex.schema.hasColumn(TableName.Organization, "rootOrgId");
|
||||||
|
if (hasParentOrgId || hasRootOrgId) {
|
||||||
await knex.schema.alterTable(TableName.Organization, (t) => {
|
await knex.schema.alterTable(TableName.Organization, (t) => {
|
||||||
t.dropColumn("parentOrgId");
|
if (hasParentOrgId) t.dropColumn("parentOrgId");
|
||||||
|
if (hasRootOrgId) t.dropColumn("rootOrgId");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ export const OrganizationsSchema = z.object({
|
|||||||
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()
|
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>;
|
||||||
|
|||||||
@@ -460,7 +460,7 @@ export const groupServiceFactory = ({
|
|||||||
const { permission } = await permissionService.getOrgPermission({
|
const { permission } = await permissionService.getOrgPermission({
|
||||||
actor,
|
actor,
|
||||||
actorId,
|
actorId,
|
||||||
actorOrgId,
|
orgId: actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
scope: OrganizationActionScope.Any
|
scope: OrganizationActionScope.Any
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ interface TPermissionDataReturn extends TMemberships {
|
|||||||
orgAuthEnforced?: boolean | null;
|
orgAuthEnforced?: boolean | null;
|
||||||
orgGoogleSsoAuthEnforced?: boolean | null;
|
orgGoogleSsoAuthEnforced?: boolean | null;
|
||||||
shouldUseNewPrivilegeSystem?: boolean | null;
|
shouldUseNewPrivilegeSystem?: boolean | null;
|
||||||
parentOrgId?: boolean | null;
|
rootOrgId?: string | null;
|
||||||
bypassOrgAuthEnabled?: boolean | null;
|
bypassOrgAuthEnabled?: boolean | null;
|
||||||
roles: {
|
roles: {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -275,7 +275,7 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
|
|||||||
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("parentOrgId").withSchema(TableName.Organization).as("parentOrgId")
|
db.ref("rootOrgId").withSchema(TableName.Organization).as("rootOrgId")
|
||||||
);
|
);
|
||||||
|
|
||||||
const data = sqlNestRelationships({
|
const data = sqlNestRelationships({
|
||||||
@@ -285,7 +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(),
|
||||||
parentOrgId: z.string().optional().nullable(),
|
rootOrgId: z.string().optional().nullable(),
|
||||||
orgGoogleSsoAuthEnforced: z.boolean(),
|
orgGoogleSsoAuthEnforced: z.boolean(),
|
||||||
bypassOrgAuthEnabled: z.boolean()
|
bypassOrgAuthEnabled: z.boolean()
|
||||||
}).parse(el),
|
}).parse(el),
|
||||||
|
|||||||
@@ -209,8 +209,8 @@ export const permissionServiceFactory = ({
|
|||||||
});
|
});
|
||||||
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 parentOrgId = permissionData?.[0]?.parentOrgId;
|
const rootOrgId = permissionData?.[0]?.rootOrgId;
|
||||||
const isChild = Boolean(parentOrgId);
|
const isChild = Boolean(rootOrgId);
|
||||||
if (scope === OrganizationActionScope.ParentOrganization && isChild) {
|
if (scope === OrganizationActionScope.ParentOrganization && isChild) {
|
||||||
throw new BadRequestError({ message: `Child organization cannot do this operation` });
|
throw new BadRequestError({ message: `Child organization cannot do this operation` });
|
||||||
} else if (scope === OrganizationActionScope.ChildOrganization && !isChild) {
|
} else if (scope === OrganizationActionScope.ChildOrganization && !isChild) {
|
||||||
|
|||||||
@@ -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[];
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export const subOrgServiceFactory = ({
|
|||||||
OrgPermissionSubjects.ChildOrganization
|
OrgPermissionSubjects.ChildOrganization
|
||||||
);
|
);
|
||||||
|
|
||||||
const orgLicensePlan = await licenseService.getPlan(permissionActor.parentOrgId);
|
const orgLicensePlan = await licenseService.getPlan(permissionActor.rootOrgId);
|
||||||
if (!orgLicensePlan.subOrganization) {
|
if (!orgLicensePlan.subOrganization) {
|
||||||
throw new BadRequestError({
|
throw new BadRequestError({
|
||||||
message: "Child organization creation failed. Please upgrade your instance to Infisical's Enterprise plan."
|
message: "Child organization creation failed. Please upgrade your instance to Infisical's Enterprise plan."
|
||||||
@@ -52,7 +52,10 @@ export const subOrgServiceFactory = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const organization = await orgDAL.transaction(async (tx) => {
|
const organization = await orgDAL.transaction(async (tx) => {
|
||||||
const org = await orgDAL.create({ name, slug: name, parentOrgId: permissionActor.orgId }, tx);
|
const org = await orgDAL.create(
|
||||||
|
{ name, slug: name, rootOrgId: permissionActor.orgId, parentOrgId: permissionActor.orgId },
|
||||||
|
tx
|
||||||
|
);
|
||||||
const membership = await membershipDAL.create(
|
const membership = await membershipDAL.create(
|
||||||
{
|
{
|
||||||
scope: AccessScope.Organization,
|
scope: AccessScope.Organization,
|
||||||
@@ -83,7 +86,7 @@ export const subOrgServiceFactory = ({
|
|||||||
actorId: permissionActor.id,
|
actorId: permissionActor.id,
|
||||||
actor: permissionActor.type,
|
actor: permissionActor.type,
|
||||||
orgId: permissionActor.parentOrgId,
|
orgId: permissionActor.parentOrgId,
|
||||||
actorOrgId: permissionActor.parentOrgId,
|
actorOrgId: permissionActor.rootOrgId,
|
||||||
actorAuthMethod: permissionActor.authMethod,
|
actorAuthMethod: permissionActor.authMethod,
|
||||||
scope: OrganizationActionScope.ParentOrganization
|
scope: OrganizationActionScope.ParentOrganization
|
||||||
});
|
});
|
||||||
@@ -91,7 +94,7 @@ export const subOrgServiceFactory = ({
|
|||||||
const organizations = await orgDAL.listSubOrganizations({
|
const organizations = await orgDAL.listSubOrganizations({
|
||||||
actorId: permissionActor.id,
|
actorId: permissionActor.id,
|
||||||
actorType: permissionActor.type,
|
actorType: permissionActor.type,
|
||||||
orgId: permissionActor.parentOrgId,
|
orgId: permissionActor.rootOrgId,
|
||||||
isAccessible: data?.isAccessible,
|
isAccessible: data?.isAccessible,
|
||||||
limit: data?.limit,
|
limit: data?.limit,
|
||||||
offset: data?.offset
|
offset: data?.offset
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ export type OrgServiceActor = {
|
|||||||
id: string;
|
id: string;
|
||||||
authMethod: ActorAuthMethod;
|
authMethod: ActorAuthMethod;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
parentOrgId: string;
|
parentOrgId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ 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;
|
parentOrgId: string;
|
||||||
authMethod: AuthMethod;
|
authMethod: AuthMethod;
|
||||||
isMfaVerified?: boolean;
|
isMfaVerified?: boolean;
|
||||||
@@ -32,6 +33,7 @@ export type TAuthMode =
|
|||||||
userId: string;
|
userId: string;
|
||||||
user: TUsers;
|
user: TUsers;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
parentOrgId: string;
|
parentOrgId: string;
|
||||||
token: string;
|
token: string;
|
||||||
}
|
}
|
||||||
@@ -41,6 +43,7 @@ export type TAuthMode =
|
|||||||
actor: ActorType.SERVICE;
|
actor: ActorType.SERVICE;
|
||||||
serviceTokenId: string;
|
serviceTokenId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
parentOrgId: string;
|
parentOrgId: string;
|
||||||
authMethod: null;
|
authMethod: null;
|
||||||
token: string;
|
token: string;
|
||||||
@@ -51,6 +54,7 @@ export type TAuthMode =
|
|||||||
identityId: string;
|
identityId: string;
|
||||||
identityName: string;
|
identityName: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
parentOrgId: string;
|
parentOrgId: string;
|
||||||
authMethod: null;
|
authMethod: null;
|
||||||
isInstanceAdmin?: boolean;
|
isInstanceAdmin?: boolean;
|
||||||
@@ -61,6 +65,7 @@ export type TAuthMode =
|
|||||||
actor: ActorType.SCIM_CLIENT;
|
actor: ActorType.SCIM_CLIENT;
|
||||||
scimTokenId: string;
|
scimTokenId: string;
|
||||||
orgId: string;
|
orgId: string;
|
||||||
|
rootOrgId: string;
|
||||||
parentOrgId: string;
|
parentOrgId: string;
|
||||||
authMethod: null;
|
authMethod: null;
|
||||||
};
|
};
|
||||||
@@ -145,10 +150,8 @@ export const injectIdentity = fp(
|
|||||||
|
|
||||||
switch (authMode) {
|
switch (authMode) {
|
||||||
case AuthMode.JWT: {
|
case AuthMode.JWT: {
|
||||||
const { user, tokenVersionId, orgId, parentOrgId } = await server.services.authToken.fnValidateJwtIdentity(
|
const { user, tokenVersionId, orgId, rootOrgId, parentOrgId } =
|
||||||
token,
|
await server.services.authToken.fnValidateJwtIdentity(token, subOrganizationSelector);
|
||||||
subOrganizationSelector
|
|
||||||
);
|
|
||||||
requestContext.set("orgId", orgId);
|
requestContext.set("orgId", orgId);
|
||||||
|
|
||||||
req.auth = {
|
req.auth = {
|
||||||
@@ -158,6 +161,7 @@ export const injectIdentity = fp(
|
|||||||
tokenVersionId,
|
tokenVersionId,
|
||||||
actor,
|
actor,
|
||||||
orgId,
|
orgId,
|
||||||
|
rootOrgId,
|
||||||
parentOrgId,
|
parentOrgId,
|
||||||
authMethod: token.authMethod,
|
authMethod: token.authMethod,
|
||||||
isMfaVerified: token.isMfaVerified,
|
isMfaVerified: token.isMfaVerified,
|
||||||
@@ -177,6 +181,7 @@ export const injectIdentity = fp(
|
|||||||
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
authMode: AuthMode.IDENTITY_ACCESS_TOKEN,
|
||||||
actor,
|
actor,
|
||||||
orgId: identity.orgId,
|
orgId: identity.orgId,
|
||||||
|
rootOrgId: identity.rootOrgId,
|
||||||
parentOrgId: identity.parentOrgId,
|
parentOrgId: identity.parentOrgId,
|
||||||
identityId: identity.identityId,
|
identityId: identity.identityId,
|
||||||
identityName: identity.name,
|
identityName: identity.name,
|
||||||
@@ -213,7 +218,8 @@ export const injectIdentity = fp(
|
|||||||
|
|
||||||
req.auth = {
|
req.auth = {
|
||||||
orgId: serviceToken.orgId,
|
orgId: serviceToken.orgId,
|
||||||
parentOrgId: 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,
|
||||||
@@ -235,7 +241,16 @@ export const injectIdentity = fp(
|
|||||||
if (subOrganizationSelector)
|
if (subOrganizationSelector)
|
||||||
throw new BadRequestError({ message: `Service token doesn't support sub organization selector` });
|
throw new BadRequestError({ message: `Service token doesn't support sub organization selector` });
|
||||||
|
|
||||||
req.auth = { authMode: AuthMode.SCIM_TOKEN, actor, scimTokenId, orgId, authMethod: null, parentOrgId: orgId };
|
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:
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const injectPermission = fp(async (server) => {
|
|||||||
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
|
parentOrgId: req.auth.parentOrgId
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ export const injectPermission = fp(async (server) => {
|
|||||||
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
|
parentOrgId: req.auth.parentOrgId
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -38,7 +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,
|
||||||
parentOrgId: req.auth.orgId,
|
rootOrgId: req.auth.rootOrgId,
|
||||||
|
parentOrgId: req.auth.parentOrgId,
|
||||||
authMethod: null
|
authMethod: null
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -50,7 +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,
|
||||||
parentOrgId: req.auth.orgId,
|
rootOrgId: req.auth.rootOrgId,
|
||||||
|
parentOrgId: req.auth.parentOrgId,
|
||||||
authMethod: null
|
authMethod: null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -76,7 +76,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.parentOrgId,
|
req.permission.rootOrgId,
|
||||||
req.permission.orgId
|
req.permission.orgId
|
||||||
);
|
);
|
||||||
return { organization };
|
return { organization };
|
||||||
|
|||||||
@@ -210,11 +210,12 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, membershipUserDAL, orgD
|
|||||||
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 orgId = "";
|
||||||
|
let rootOrgId = "";
|
||||||
let parentOrgId = "";
|
let parentOrgId = "";
|
||||||
if (token.organizationId) {
|
if (token.organizationId) {
|
||||||
if (subOrganizationSelector) {
|
if (subOrganizationSelector) {
|
||||||
const subOrganization = await orgDAL.findOne({
|
const subOrganization = await orgDAL.findOne({
|
||||||
parentOrgId: token.organizationId,
|
rootOrgId: token.organizationId,
|
||||||
slug: subOrganizationSelector
|
slug: subOrganizationSelector
|
||||||
});
|
});
|
||||||
if (!subOrganization)
|
if (!subOrganization)
|
||||||
@@ -234,7 +235,8 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, membershipUserDAL, orgD
|
|||||||
throw new ForbiddenRequestError({ message: "User organization membership is inactive" });
|
throw new ForbiddenRequestError({ message: "User organization membership is inactive" });
|
||||||
}
|
}
|
||||||
orgId = subOrganization.id;
|
orgId = subOrganization.id;
|
||||||
parentOrgId = token.organizationId;
|
rootOrgId = token.organizationId;
|
||||||
|
parentOrgId = subOrganization.parentOrgId;
|
||||||
} else {
|
} else {
|
||||||
const orgMembership = await membershipUserDAL.findOne({
|
const orgMembership = await membershipUserDAL.findOne({
|
||||||
actorUserId: user.id,
|
actorUserId: user.id,
|
||||||
@@ -251,11 +253,12 @@ export const tokenServiceFactory = ({ tokenDAL, userDAL, membershipUserDAL, orgD
|
|||||||
}
|
}
|
||||||
|
|
||||||
orgId = token.organizationId;
|
orgId = token.organizationId;
|
||||||
|
rootOrgId = token.organizationId;
|
||||||
parentOrgId = token.organizationId;
|
parentOrgId = token.organizationId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return { user, tokenVersionId: token.tokenVersionId, orgId, parentOrgId };
|
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;
|
||||||
|
|||||||
@@ -210,10 +210,12 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
let orgId = "";
|
let orgId = "";
|
||||||
const parentOrgId = identityAccessToken.identityScopeOrgId;
|
let parentOrgId = "";
|
||||||
|
const identityOrgDetails = await orgDAL.findOne({ id: identityAccessToken.identityScopeOrgId });
|
||||||
|
const rootOrgId = identityOrgDetails.rootOrgId || identityOrgDetails.id;
|
||||||
|
|
||||||
if (subOrganizationSelector) {
|
if (subOrganizationSelector) {
|
||||||
const subOrganization = await orgDAL.findOne({ parentOrgId, slug: subOrganizationSelector });
|
const subOrganization = await orgDAL.findOne({ rootOrgId, slug: subOrganizationSelector });
|
||||||
if (!subOrganizationSelector)
|
if (!subOrganizationSelector)
|
||||||
throw new BadRequestError({ message: `Sub organization ${subOrganizationSelector} not found` });
|
throw new BadRequestError({ message: `Sub organization ${subOrganizationSelector} not found` });
|
||||||
|
|
||||||
@@ -227,18 +229,20 @@ export const identityAccessTokenServiceFactory = ({
|
|||||||
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;
|
orgId = subOrganization.id;
|
||||||
|
parentOrgId = subOrganization.parentOrgId as string;
|
||||||
} else {
|
} else {
|
||||||
const identityOrgMembership = await membershipIdentityDAL.findOne({
|
const identityOrgMembership = await membershipIdentityDAL.findOne({
|
||||||
scope: AccessScope.Organization,
|
scope: AccessScope.Organization,
|
||||||
actorIdentityId: identityAccessToken.identityId,
|
actorIdentityId: identityAccessToken.identityId,
|
||||||
scopeOrgId: parentOrgId
|
scopeOrgId: rootOrgId
|
||||||
});
|
});
|
||||||
|
|
||||||
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 = parentOrgId;
|
orgId = rootOrgId;
|
||||||
|
parentOrgId = rootOrgId;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { accessTokenNumUses } = identityAccessToken;
|
let { accessTokenNumUses } = identityAccessToken;
|
||||||
@@ -249,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, parentOrgId };
|
return { ...identityAccessToken, orgId, rootOrgId, parentOrgId };
|
||||||
};
|
};
|
||||||
|
|
||||||
return { renewAccessToken, revokeAccessToken, fnValidateIdentityAccessToken };
|
return { renewAccessToken, revokeAccessToken, fnValidateIdentityAccessToken };
|
||||||
|
|||||||
@@ -291,5 +291,13 @@ export const membershipUserDALFactory = (db: TDbClient) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// const listAvailableUsers = async (scopeData: AccessScopeData) => {
|
||||||
|
// try {
|
||||||
|
// const query = await db.replicaNode()(TableName.Membership).where(`${TableName.Membership}.scopeOrgId`);
|
||||||
|
// } catch (error) {
|
||||||
|
// throw new DatabaseError({ error, name: "ListAvailableUsers" });
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
return { ...orm, findUsers, getUserById };
|
return { ...orm, findUsers, getUserById };
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
const buildBaseQuery = (orgIdSubquery: Knex.QueryBuilder) => {
|
const buildBaseQuery = (orgIdSubquery: Knex.QueryBuilder) => {
|
||||||
return db
|
return db
|
||||||
.replicaNode()(TableName.Organization)
|
.replicaNode()(TableName.Organization)
|
||||||
.whereNull(`${TableName.Organization}.parentOrgId`)
|
.whereNull(`${TableName.Organization}.rootOrgId`)
|
||||||
.whereIn(`${TableName.Organization}.id`, orgIdSubquery)
|
.whereIn(`${TableName.Organization}.id`, orgIdSubquery)
|
||||||
.leftJoin(TableName.Project, `${TableName.Organization}.id`, `${TableName.Project}.orgId`)
|
.leftJoin(TableName.Project, `${TableName.Organization}.id`, `${TableName.Project}.orgId`)
|
||||||
.leftJoin(TableName.Membership, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
.leftJoin(TableName.Membership, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
||||||
@@ -168,7 +168,7 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
// TODO(sub-org:group): check this when implement group support
|
// TODO(sub-org:group): check this when implement group support
|
||||||
const query = db
|
const query = db
|
||||||
.replicaNode()(TableName.Organization)
|
.replicaNode()(TableName.Organization)
|
||||||
.where(`${TableName.Organization}.parentOrgId`, dto.orgId)
|
.where(`${TableName.Organization}.rootOrgId`, dto.orgId)
|
||||||
.select(selectAllTableCols(TableName.Organization));
|
.select(selectAllTableCols(TableName.Organization));
|
||||||
|
|
||||||
if (dto.isAccessible) {
|
if (dto.isAccessible) {
|
||||||
@@ -196,7 +196,7 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
const org = (await db
|
const org = (await db
|
||||||
.replicaNode()(TableName.Organization)
|
.replicaNode()(TableName.Organization)
|
||||||
.where({ [`${TableName.Organization}.id` as "id"]: orgId })
|
.where({ [`${TableName.Organization}.id` as "id"]: orgId })
|
||||||
.whereNull(`${TableName.Organization}.parentOrgId`)
|
.whereNull(`${TableName.Organization}.rootOrgId`)
|
||||||
.leftJoin(TableName.SamlConfig, (qb) => {
|
.leftJoin(TableName.SamlConfig, (qb) => {
|
||||||
qb.on(`${TableName.SamlConfig}.orgId`, "=", `${TableName.Organization}.id`).andOn(
|
qb.on(`${TableName.SamlConfig}.orgId`, "=", `${TableName.Organization}.id`).andOn(
|
||||||
`${TableName.SamlConfig}.isActive`,
|
`${TableName.SamlConfig}.isActive`,
|
||||||
@@ -233,7 +233,7 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
try {
|
try {
|
||||||
const org = (await db
|
const org = (await db
|
||||||
.replicaNode()(TableName.Organization)
|
.replicaNode()(TableName.Organization)
|
||||||
.whereNull(`${TableName.Organization}.parentOrgId`)
|
.whereNull(`${TableName.Organization}.rootOrgId`)
|
||||||
.where({ [`${TableName.Organization}.slug` as "slug"]: orgSlug })
|
.where({ [`${TableName.Organization}.slug` as "slug"]: orgSlug })
|
||||||
.leftJoin(TableName.SamlConfig, (qb) => {
|
.leftJoin(TableName.SamlConfig, (qb) => {
|
||||||
qb.on(`${TableName.SamlConfig}.orgId`, "=", `${TableName.Organization}.id`).andOn(
|
qb.on(`${TableName.SamlConfig}.orgId`, "=", `${TableName.Organization}.id`).andOn(
|
||||||
@@ -279,7 +279,7 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
.whereNotNull(`${TableName.Membership}.actorUserId`)
|
||||||
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
.join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`)
|
.join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`)
|
||||||
.whereNull(`${TableName.Organization}.parentOrgId`)
|
.whereNull(`${TableName.Organization}.rootOrgId`)
|
||||||
.leftJoin(TableName.SamlConfig, (qb) => {
|
.leftJoin(TableName.SamlConfig, (qb) => {
|
||||||
qb.on(`${TableName.SamlConfig}.orgId`, "=", `${TableName.Organization}.id`).andOn(
|
qb.on(`${TableName.SamlConfig}.orgId`, "=", `${TableName.Organization}.id`).andOn(
|
||||||
`${TableName.SamlConfig}.isActive`,
|
`${TableName.SamlConfig}.isActive`,
|
||||||
@@ -651,7 +651,7 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
})
|
})
|
||||||
.join(TableName.Users, `${TableName.Users}.id`, `${TableName.Membership}.actorUserId`)
|
.join(TableName.Users, `${TableName.Users}.id`, `${TableName.Membership}.actorUserId`)
|
||||||
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
|
||||||
.whereNull(`${TableName.Organization}.parentOrgId`)
|
.whereNull(`${TableName.Organization}.rootOrgId`)
|
||||||
.leftJoin(TableName.UserAliases, function joinUserAlias() {
|
.leftJoin(TableName.UserAliases, function joinUserAlias() {
|
||||||
this.on(`${TableName.UserAliases}.userId`, "=", `${TableName.Membership}.actorUserId`)
|
this.on(`${TableName.UserAliases}.userId`, "=", `${TableName.Membership}.actorUserId`)
|
||||||
.andOn(`${TableName.UserAliases}.orgId`, "=", `${TableName.Membership}.scopeOrgId`)
|
.andOn(`${TableName.UserAliases}.orgId`, "=", `${TableName.Membership}.scopeOrgId`)
|
||||||
@@ -690,7 +690,7 @@ export const orgDALFactory = (db: TDbClient) => {
|
|||||||
.replicaNode()(TableName.Membership)
|
.replicaNode()(TableName.Membership)
|
||||||
.where({ actorIdentityId: identityId })
|
.where({ actorIdentityId: identityId })
|
||||||
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
|
||||||
.whereNull(`${TableName.Organization}.parentOrgId`)
|
.whereNull(`${TableName.Organization}.rootOrgId`)
|
||||||
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
|
||||||
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
|
||||||
.join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`)
|
.join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`)
|
||||||
|
|||||||
@@ -157,7 +157,7 @@ export const orgServiceFactory = ({
|
|||||||
userId: string,
|
userId: string,
|
||||||
orgId: string,
|
orgId: string,
|
||||||
actorAuthMethod: ActorAuthMethod,
|
actorAuthMethod: ActorAuthMethod,
|
||||||
parentOrgId: string,
|
rootOrgId: string,
|
||||||
actorOrgId: string
|
actorOrgId: string
|
||||||
) => {
|
) => {
|
||||||
await permissionService.getOrgPermission({
|
await permissionService.getOrgPermission({
|
||||||
@@ -165,17 +165,17 @@ export const orgServiceFactory = ({
|
|||||||
actorId: userId,
|
actorId: userId,
|
||||||
orgId,
|
orgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
actorOrgId: parentOrgId,
|
actorOrgId: rootOrgId,
|
||||||
scope: OrganizationActionScope.Any
|
scope: OrganizationActionScope.Any
|
||||||
});
|
});
|
||||||
const appCfg = getConfig();
|
const appCfg = getConfig();
|
||||||
const org = await orgDAL.findOrgById(orgId);
|
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 hasSubOrg = actorOrgId !== parentOrgId;
|
const hasSubOrg = actorOrgId !== rootOrgId;
|
||||||
let subOrg;
|
let subOrg;
|
||||||
if (hasSubOrg) {
|
if (hasSubOrg) {
|
||||||
subOrg = await orgDAL.findOne({ parentOrgId, id: actorOrgId });
|
subOrg = await orgDAL.findOne({ rootOrgId, id: actorOrgId });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!org.userTokenExpiration) {
|
if (!org.userTokenExpiration) {
|
||||||
|
|||||||
@@ -298,7 +298,6 @@ export const projectServiceFactory = ({
|
|||||||
projectTemplate = await projectTemplateService.findProjectTemplateByName(template, {
|
projectTemplate = await projectTemplateService.findProjectTemplateByName(template, {
|
||||||
id: actorId,
|
id: actorId,
|
||||||
orgId: organization.id,
|
orgId: organization.id,
|
||||||
parentOrgId: organization.id,
|
|
||||||
type: actor,
|
type: actor,
|
||||||
authMethod: actorAuthMethod
|
authMethod: actorAuthMethod
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,10 +25,12 @@ import {
|
|||||||
TGetServiceTokenInfoDTO,
|
TGetServiceTokenInfoDTO,
|
||||||
TProjectServiceTokensDTO
|
TProjectServiceTokensDTO
|
||||||
} from "./service-token-types";
|
} from "./service-token-types";
|
||||||
|
import { TOrgDALFactory } from "../org/org-dal";
|
||||||
|
|
||||||
type TServiceTokenServiceFactoryDep = {
|
type TServiceTokenServiceFactoryDep = {
|
||||||
serviceTokenDAL: TServiceTokenDALFactory;
|
serviceTokenDAL: TServiceTokenDALFactory;
|
||||||
userDAL: TUserDALFactory;
|
userDAL: TUserDALFactory;
|
||||||
|
orgDAL: Pick<TOrgDALFactory, "findById">;
|
||||||
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
permissionService: Pick<TPermissionServiceFactory, "getProjectPermission">;
|
||||||
projectEnvDAL: Pick<TProjectEnvDALFactory, "findBySlugs">;
|
projectEnvDAL: Pick<TProjectEnvDALFactory, "findBySlugs">;
|
||||||
projectDAL: Pick<TProjectDALFactory, "findById">;
|
projectDAL: Pick<TProjectDALFactory, "findById">;
|
||||||
@@ -45,7 +47,8 @@ export const serviceTokenServiceFactory = ({
|
|||||||
projectEnvDAL,
|
projectEnvDAL,
|
||||||
projectDAL,
|
projectDAL,
|
||||||
accessTokenQueue,
|
accessTokenQueue,
|
||||||
smtpService
|
smtpService,
|
||||||
|
orgDAL
|
||||||
}: TServiceTokenServiceFactoryDep) => {
|
}: TServiceTokenServiceFactoryDep) => {
|
||||||
const createServiceToken = async ({
|
const createServiceToken = async ({
|
||||||
iv,
|
iv,
|
||||||
@@ -184,7 +187,15 @@ export const serviceTokenServiceFactory = ({
|
|||||||
if (!isMatch) throw new UnauthorizedError({ message: "Invalid service token" });
|
if (!isMatch) throw new UnauthorizedError({ message: "Invalid service token" });
|
||||||
await accessTokenQueue.updateServiceTokenStatus(serviceToken.id);
|
await accessTokenQueue.updateServiceTokenStatus(serviceToken.id);
|
||||||
|
|
||||||
return { ...serviceToken, lastUsed: new Date(), orgId: project.orgId };
|
const serviceTokenOrgDetails = await orgDAL.findById(project.orgId);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...serviceToken,
|
||||||
|
lastUsed: new Date(),
|
||||||
|
orgId: project.orgId,
|
||||||
|
parentOrgId: serviceTokenOrgDetails.parentOrgId || serviceTokenOrgDetails.id,
|
||||||
|
rootOrgId: serviceTokenOrgDetails.rootOrgId || serviceTokenOrgDetails.id
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const notifyExpiringTokens = async () => {
|
const notifyExpiringTokens = async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user