feat: resolved all missing things

This commit is contained in:
=
2025-10-10 00:09:47 +05:30
parent 3fa63a033e
commit 879bc00eeb
14 changed files with 134 additions and 46 deletions
@@ -16,6 +16,9 @@ import { selectAllTableCols, sqlNestRelationships } from "@app/lib/knex";
import { ActorType } from "@app/services/auth/auth-type";
interface TPermissionDataReturn extends TMemberships {
orgAuthEnforced?: boolean | null;
orgGoogleSsoAuthEnforced?: boolean | null;
bypassOrgAuthEnabled?: boolean | null;
roles: {
id: string;
createdAt: Date;
@@ -177,6 +180,7 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
const docs = await (tx || db)
.replicaNode()(TableName.Membership)
.join(TableName.MembershipRole, `${TableName.Membership}.id`, `${TableName.MembershipRole}.membershipId`)
.join(TableName.Organization, `${TableName.Membership}.scopeOrgId`, `${TableName.Organization}.id`)
.leftJoin(TableName.Role, `${TableName.MembershipRole}.customRoleId`, `${TableName.Role}.id`)
.leftJoin(TableName.AdditionalPrivilege, (qb) => {
if (actorType === ActorType.IDENTITY) {
@@ -264,13 +268,22 @@ export const permissionDALFactory = (db: TDbClient): TPermissionDALFactory => {
db.ref("updatedAt").withSchema(TableName.AdditionalPrivilege).as("additionalPrivilegeUpdatedAt"),
db.ref("id").withSchema(TableName.IdentityMetadata).as("metadataId"),
db.ref("key").withSchema(TableName.IdentityMetadata).as("metadataKey"),
db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue")
db.ref("value").withSchema(TableName.IdentityMetadata).as("metadataValue"),
db.ref("shouldUseNewPrivilegeSystem").withSchema(TableName.Organization),
db.ref("authEnforced").withSchema(TableName.Organization).as("orgAuthEnforced"),
db.ref("googleSsoAuthEnforced").withSchema(TableName.Organization).as("orgGoogleSsoAuthEnforced"),
db.ref("bypassOrgAuthEnabled").withSchema(TableName.Organization).as("bypassOrgAuthEnabled")
);
const data = sqlNestRelationships({
data: docs,
key: "id",
parentMapper: (el) => MembershipsSchema.parse(el),
parentMapper: (el) =>
MembershipsSchema.extend({
orgAuthEnforced: z.boolean().optional().nullable(),
orgGoogleSsoAuthEnforced: z.boolean(),
bypassOrgAuthEnabled: z.boolean()
}).parse(el),
childrenMapper: [
{
key: "additionalPrivilegeId",
@@ -2,7 +2,7 @@
import { ForbiddenError, MongoAbility, PureAbility, subject } from "@casl/ability";
import { z } from "zod";
import { OrgMembershipRole, TOrganizations } from "@app/db/schemas";
import { TOrganizations } from "@app/db/schemas";
import { validatePermissionBoundary } from "@app/lib/casl/boundary";
import { BadRequestError, ForbiddenRequestError, UnauthorizedError } from "@app/lib/errors";
import { ActorAuthMethod, AuthMethod } from "@app/services/auth/auth-type";
@@ -123,13 +123,13 @@ function validateOrgSSO(
isOrgSsoEnforced: TOrganizations["authEnforced"],
isOrgGoogleSsoEnforced: TOrganizations["googleSsoAuthEnforced"],
isOrgSsoBypassEnabled: TOrganizations["bypassOrgAuthEnabled"],
orgRole: OrgMembershipRole
isAdmin: boolean
) {
if (actorAuthMethod === undefined) {
throw new UnauthorizedError({ name: "No auth method defined" });
}
if ((isOrgSsoEnforced || isOrgGoogleSsoEnforced) && isOrgSsoBypassEnabled && orgRole === OrgMembershipRole.Admin) {
if ((isOrgSsoEnforced || isOrgGoogleSsoEnforced) && isOrgSsoBypassEnabled && isAdmin) {
return;
}
@@ -32,7 +32,7 @@ import { TUserDALFactory } from "@app/services/user/user-dal";
import { orgAdminPermissions, orgMemberPermissions, orgNoAccessPermissions, OrgPermissionSet } from "./org-permission";
import { TPermissionDALFactory } from "./permission-dal";
import { escapeHandlebarsMissingDict } from "./permission-fns";
import { escapeHandlebarsMissingDict, validateOrgSSO } from "./permission-fns";
import {
TBuildOrgPermissionDTO,
TBuildProjectPermissionDTO,
@@ -223,24 +223,25 @@ export const permissionServiceFactory = ({
return activeRoles.concat(activeAdditionalPrivileges);
});
const hasRole = (role: string) =>
permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role)));
validateOrgSSO(
authMethod,
permissionData?.[0].orgAuthEnforced,
Boolean(permissionData?.[0].orgGoogleSsoAuthEnforced),
Boolean(permissionData?.[0].bypassOrgAuthEnabled),
hasRole(OrgMembershipRole.Admin)
);
const permission = createMongoAbility<OrgPermissionSet>(buildOrgPermissionRules(permissionFromRoles), {
conditionsMatcher
});
// TODO(simp): validate this
// validateOrgSSO(
// authMethod,
// membership.orgAuthEnforced,
// membership.orgGoogleSsoAuthEnforced,
// membership.bypassOrgAuthEnabled,
// membership.role as OrgMembershipRole
// );
return {
permission,
memberships: permissionData,
hasRole: (role: string) =>
permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role)))
hasRole
};
};
@@ -367,13 +368,16 @@ export const permissionServiceFactory = ({
return activeRoles.concat(activeAdditionalPrivileges);
});
// validateOrgSSO(
// authMethod,
// userProjectPermission.orgAuthEnforced,
// userProjectPermission.orgGoogleSsoAuthEnforced,
// userProjectPermission.bypassOrgAuthEnabled,
// userProjectPermission.orgRole
// );
const hasRole = (role: string) =>
permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role)));
validateOrgSSO(
actorAuthMethod,
permissionData?.[0].orgAuthEnforced,
Boolean(permissionData?.[0].orgGoogleSsoAuthEnforced),
Boolean(permissionData?.[0].bypassOrgAuthEnabled),
hasRole(ProjectMembershipRole.Admin)
);
const rules = buildProjectPermissionRules(permissionFromRoles);
const templatedRules = handlebars.compile(JSON.stringify(rules), { data: false });
@@ -422,8 +426,7 @@ export const permissionServiceFactory = ({
return {
permission,
memberships: permissionData,
hasRole: (role: string) =>
permissionData.some((memberships) => memberships.roles.some((el) => role === (el.customRoleSlug || el.role)))
hasRole
};
};
+6 -2
View File
@@ -19,6 +19,7 @@ import { getConfig } from "@app/lib/config/env";
import { crypto } from "@app/lib/crypto";
import { BadRequestError, NotFoundError, ScimRequestError, UnauthorizedError } from "@app/lib/errors";
import { alphaNumericNanoId } from "@app/lib/nanoid";
import { TAdditionalPrivilegeDALFactory } from "@app/services/additional-privilege/additional-privilege-dal";
import { AuthTokenType } from "@app/services/auth/auth-type";
import { TExternalGroupOrgRoleMappingDALFactory } from "@app/services/external-group-org-role-mapping/external-group-org-role-mapping-dal";
import { TMembershipRoleDALFactory } from "@app/services/membership/membership-role-dal";
@@ -93,6 +94,7 @@ type TScimServiceFactoryDep = {
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
smtpService: Pick<TSmtpService, "sendMail">;
externalGroupOrgRoleMappingDAL: TExternalGroupOrgRoleMappingDALFactory;
additionalPrivilegeDAL: TAdditionalPrivilegeDALFactory;
};
export const scimServiceFactory = ({
@@ -111,7 +113,8 @@ export const scimServiceFactory = ({
externalGroupOrgRoleMappingDAL,
membershipGroupDAL,
membershipUserDAL,
membershipRoleDAL
membershipRoleDAL,
additionalPrivilegeDAL
}: TScimServiceFactoryDep): TScimServiceFactory => {
const createScimToken: TScimServiceFactory["createScimToken"] = async ({
actor,
@@ -673,7 +676,8 @@ export const scimServiceFactory = ({
licenseService,
membershipUserDAL,
membershipRoleDAL,
userGroupMembershipDAL
userGroupMembershipDAL,
additionalPrivilegeDAL
});
return {}; // intentionally return empty object upon success