Skip to content

Commit

Permalink
Merge pull request #1192 from Infisical/stv3-org-roles
Browse files Browse the repository at this point in the history
Add Identities + Universal Auth Authentication Method
  • Loading branch information
maidul98 authored Dec 10, 2023
2 parents aabd896 + 4f6adb5 commit f3e8ef1
Show file tree
Hide file tree
Showing 152 changed files with 6,740 additions and 3,053 deletions.
22 changes: 15 additions & 7 deletions backend/src/controllers/v1/authController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,22 @@ import jwt from "jsonwebtoken";
import * as bigintConversion from "bigint-conversion";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const jsrp = require("jsrp");
import { LoginSRPDetail, TokenVersion, User } from "../../models";
import {
LoginSRPDetail,
TokenVersion,
User
} from "../../models";
import { clearTokens, createToken, issueAuthTokens } from "../../helpers/auth";
import { checkUserDevice } from "../../helpers/user";
import { AuthTokenType } from "../../variables";
import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors";
import {
BadRequestError,
UnauthorizedRequestError
} from "../../utils/errors";
import {
getAuthSecret,
getHttpsEnabled,
getJwtAuthLifetime
getJwtAuthLifetime,
} from "../../config";
import { ActorType } from "../../ee/models";
import { validateRequest } from "../../helpers/validation";
Expand All @@ -25,10 +32,11 @@ declare module "jsonwebtoken" {
userId: string;
refreshVersion?: number;
}
export interface ServiceRefreshTokenJwtPayload extends jwt.JwtPayload {
serviceTokenDataId: string;
export interface IdentityAccessTokenJwtPayload extends jwt.JwtPayload {
_id: string;
clientSecretId: string;
identityAccessTokenId: string;
authTokenType: string;
tokenVersion: number;
}
}

Expand Down Expand Up @@ -266,4 +274,4 @@ export const getNewToken = async (req: Request, res: Response) => {

export const handleAuthProviderCallback = (req: Request, res: Response) => {
res.redirect(`/login/provider/success?token=${encodeURIComponent(req.providerAuthToken)}`);
};
};
2 changes: 2 additions & 0 deletions backend/src/controllers/v1/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as authController from "./authController";
import * as universalAuthController from "./universalAuthController";
import * as botController from "./botController";
import * as integrationAuthController from "./integrationAuthController";
import * as integrationController from "./integrationController";
Expand All @@ -20,6 +21,7 @@ import * as adminController from "./adminController";

export {
authController,
universalAuthController,
botController,
integrationAuthController,
integrationController,
Expand Down
13 changes: 10 additions & 3 deletions backend/src/controllers/v1/membershipController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { IUser, Key, Membership, MembershipOrg, User, Workspace } from "../../mo
import { EventType, Role } from "../../ee/models";
import { deleteMembership as deleteMember, findMembership } from "../../helpers/membership";
import { sendMail } from "../../helpers/nodemailer";
import { ACCEPTED, ADMIN, CUSTOM, MEMBER, VIEWER } from "../../variables";
import { ACCEPTED, ADMIN, CUSTOM, MEMBER, NO_ACCESS, VIEWER } from "../../variables";
import { getSiteURL } from "../../config";
import { EEAuditLogService } from "../../ee/services";
import { EEAuditLogService, EELicenseService } from "../../ee/services";
import { validateRequest } from "../../helpers/validation";
import * as reqValidator from "../../validation/membership";
import {
Expand Down Expand Up @@ -129,14 +129,21 @@ export const changeMembershipRole = async (req: Request, res: Response) => {
ProjectPermissionSub.Member
);

const isCustomRole = ![ADMIN, MEMBER, VIEWER].includes(role);
const isCustomRole = ![ADMIN, MEMBER, VIEWER, NO_ACCESS].includes(role);
if (isCustomRole) {
const wsRole = await Role.findOne({
slug: role,
isOrgRole: false,
workspace: membershipToChangeRole.workspace
});
if (!wsRole) throw BadRequestError({ message: "Role not found" });

const plan = await EELicenseService.getPlan(wsRole.organization);

if (!plan.rbac) return res.status(400).send({
message: "Failed to assign custom role due to RBAC restriction. Upgrade plan to assign custom role to member."
});

const membership = await Membership.findByIdAndUpdate(membershipId, {
role: CUSTOM,
customRole: wsRole
Expand Down
19 changes: 12 additions & 7 deletions backend/src/controllers/v1/membershipOrgController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { validateRequest } from "../../helpers/validation";
import {
OrgPermissionActions,
OrgPermissionSubjects,
getUserOrgPermissions
getAuthDataOrgPermissions
} from "../../ee/services/RoleService";
import { ForbiddenError } from "@casl/ability";

Expand All @@ -44,11 +44,12 @@ export const deleteMembershipOrg = async (req: Request, _res: Response) => {
if (!membershipOrgToDelete) {
throw new Error("Failed to delete organization membership that doesn't exist");
}

const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: membershipOrgToDelete.organization
});

const { permission, membership: membershipOrg } = await getUserOrgPermissions(
req.user._id,
membershipOrgToDelete.organization.toString()
);
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Delete,
OrgPermissionSubjects.Member
Expand All @@ -60,7 +61,7 @@ export const deleteMembershipOrg = async (req: Request, _res: Response) => {
});

await updateSubscriptionOrgQuantity({
organizationId: membershipOrg.organization.toString()
organizationId: membershipOrgToDelete.organization.toString()
});

return membershipOrgToDelete;
Expand Down Expand Up @@ -96,7 +97,11 @@ export const inviteUserToOrganization = async (req: Request, res: Response) => {
body: { inviteeEmail, organizationId }
} = await validateRequest(reqValidator.InviteUserToOrgv1, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});

ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create,
OrgPermissionSubjects.Member
Expand Down
51 changes: 40 additions & 11 deletions backend/src/controllers/v1/organizationController.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Request, Response } from "express";
import { Types } from "mongoose";
import {
IncidentContactOrg,
Membership,
Expand All @@ -14,7 +15,7 @@ import { ACCEPTED } from "../../variables";
import {
OrgPermissionActions,
OrgPermissionSubjects,
getUserOrgPermissions
getAuthDataOrgPermissions
} from "../../ee/services/RoleService";
import { OrganizationNotFoundError } from "../../utils/errors";
import { ForbiddenError } from "@casl/ability";
Expand Down Expand Up @@ -44,7 +45,10 @@ export const getOrganization = async (req: Request, res: Response) => {
} = await validateRequest(reqValidator.GetOrgv1, req);

// ensure user has membership
await getUserOrgPermissions(req.user._id, organizationId);
await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
})

const organization = await Organization.findById(organizationId);
if (!organization) {
Expand All @@ -68,8 +72,12 @@ export const getOrganizationMembers = async (req: Request, res: Response) => {
const {
params: { organizationId }
} = await validateRequest(reqValidator.GetOrgMembersv1, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);

const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});

ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read,
OrgPermissionSubjects.Member
Expand All @@ -95,7 +103,10 @@ export const getOrganizationWorkspaces = async (req: Request, res: Response) =>
params: { organizationId }
} = await validateRequest(reqValidator.GetOrgWorkspacesv1, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
})
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read,
OrgPermissionSubjects.Workspace
Expand Down Expand Up @@ -137,7 +148,10 @@ export const changeOrganizationName = async (req: Request, res: Response) => {
body: { name }
} = await validateRequest(reqValidator.ChangeOrgNamev1, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit,
OrgPermissionSubjects.Settings
Expand Down Expand Up @@ -172,7 +186,10 @@ export const getOrganizationIncidentContacts = async (req: Request, res: Respons
params: { organizationId }
} = await validateRequest(reqValidator.GetOrgIncidentContactv1, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read,
OrgPermissionSubjects.IncidentAccount
Expand All @@ -199,7 +216,10 @@ export const addOrganizationIncidentContact = async (req: Request, res: Response
body: { email }
} = await validateRequest(reqValidator.CreateOrgIncideContact, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create,
OrgPermissionSubjects.IncidentAccount
Expand Down Expand Up @@ -228,7 +248,10 @@ export const deleteOrganizationIncidentContact = async (req: Request, res: Respo
body: { email }
} = await validateRequest(reqValidator.DelOrgIncideContact, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Delete,
OrgPermissionSubjects.IncidentAccount
Expand Down Expand Up @@ -257,7 +280,10 @@ export const createOrganizationPortalSession = async (req: Request, res: Respons
params: { organizationId }
} = await validateRequest(reqValidator.GetOrgPlanBillingInfov1, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit,
OrgPermissionSubjects.Billing
Expand Down Expand Up @@ -321,7 +347,10 @@ export const getOrganizationMembersAndTheirWorkspaces = async (req: Request, res
params: { organizationId }
} = await validateRequest(reqValidator.GetOrgMembersv1, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read,
OrgPermissionSubjects.Member
Expand Down
28 changes: 19 additions & 9 deletions backend/src/controllers/v1/secretScanningController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import * as reqValidator from "../../validation/secretScanning";
import {
OrgPermissionActions,
OrgPermissionSubjects,
getUserOrgPermissions
getAuthDataOrgPermissions
} from "../../ee/services/RoleService";
import { ForbiddenError } from "@casl/ability";

Expand All @@ -37,8 +37,11 @@ export const createInstallationSession = async (req: Request, res: Response) =>
message: "Failed to find organization"
});
}

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);

const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Create,
OrgPermissionSubjects.SecretScanning
Expand Down Expand Up @@ -70,11 +73,12 @@ export const linkInstallationToOrganization = async (req: Request, res: Response
if (!installationSession) {
throw UnauthorizedRequestError();
}

const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: installationSession.organization
});

const { permission } = await getUserOrgPermissions(
req.user._id,
installationSession.organization.toString()
);
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit,
OrgPermissionSubjects.SecretScanning
Expand Down Expand Up @@ -142,7 +146,10 @@ export const getRisksForOrganization = async (req: Request, res: Response) => {
params: { organizationId }
} = await validateRequest(reqValidator.GetOrgRisksv1, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Read,
OrgPermissionSubjects.SecretScanning
Expand All @@ -162,7 +169,10 @@ export const updateRisksStatus = async (req: Request, res: Response) => {
body: { status }
} = await validateRequest(reqValidator.UpdateRiskStatusv1, req);

const { permission } = await getUserOrgPermissions(req.user._id, organizationId);
const { permission } = await getAuthDataOrgPermissions({
authData: req.authData,
organizationId: new Types.ObjectId(organizationId)
});
ForbiddenError.from(permission).throwUnlessCan(
OrgPermissionActions.Edit,
OrgPermissionSubjects.SecretScanning
Expand Down
Loading

0 comments on commit f3e8ef1

Please sign in to comment.