mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
fix expired client secret logic
This commit is contained in:
@@ -21,16 +21,16 @@ import {
|
|||||||
import { validateRequest } from "../../../helpers/validation";
|
import { validateRequest } from "../../../helpers/validation";
|
||||||
import * as reqValidator from "../../../validation/machineIdentity";
|
import * as reqValidator from "../../../validation/machineIdentity";
|
||||||
import { createToken } from "../../../helpers/auth";
|
import { createToken } from "../../../helpers/auth";
|
||||||
import {
|
import {
|
||||||
getAuthDataOrgPermissions,
|
getAuthDataOrgPermissions,
|
||||||
getOrgRolePermissions,
|
getOrgRolePermissions,
|
||||||
isAtLeastAsPrivilegedOrg
|
isAtLeastAsPrivilegedOrg
|
||||||
} from "../../services/RoleService";
|
} from "../../services/RoleService";
|
||||||
import {
|
import {
|
||||||
BadRequestError,
|
BadRequestError,
|
||||||
ForbiddenRequestError,
|
ForbiddenRequestError,
|
||||||
ResourceNotFoundError,
|
ResourceNotFoundError,
|
||||||
UnauthorizedRequestError
|
UnauthorizedRequestError
|
||||||
} from "../../../utils/errors";
|
} from "../../../utils/errors";
|
||||||
import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip";
|
import { extractIPDetails, isValidIpOrCidr } from "../../../utils/ip";
|
||||||
import { EEAuditLogService, EELicenseService } from "../../services";
|
import { EEAuditLogService, EELicenseService } from "../../services";
|
||||||
@@ -69,11 +69,11 @@ export const getMIClientSecrets = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const machineMembershipOrg = await MachineMembershipOrg.findOne({
|
const machineMembershipOrg = await MachineMembershipOrg.findOne({
|
||||||
machineIdentity: new Types.ObjectId(machineId)
|
machineIdentity: new Types.ObjectId(machineId)
|
||||||
}).populate<{
|
}).populate<{
|
||||||
machineIdentity: IMachineIdentity,
|
machineIdentity: IMachineIdentity,
|
||||||
customRole: IRole
|
customRole: IRole
|
||||||
}>("machineIdentity customRole");
|
}>("machineIdentity customRole");
|
||||||
|
|
||||||
if (!machineMembershipOrg) throw ResourceNotFoundError();
|
if (!machineMembershipOrg) throw ResourceNotFoundError();
|
||||||
|
|
||||||
const { permission } = await getAuthDataOrgPermissions({
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
@@ -86,11 +86,11 @@ export const getMIClientSecrets = async (req: Request, res: Response) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const rolePermission = await getOrgRolePermissions(
|
const rolePermission = await getOrgRolePermissions(
|
||||||
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
||||||
machineMembershipOrg.organization.toString()
|
machineMembershipOrg.organization.toString()
|
||||||
);
|
);
|
||||||
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
||||||
|
|
||||||
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
message: "Failed to get client secrets for more privileged MI"
|
message: "Failed to get client secrets for more privileged MI"
|
||||||
});
|
});
|
||||||
@@ -102,7 +102,7 @@ export const getMIClientSecrets = async (req: Request, res: Response) => {
|
|||||||
})
|
})
|
||||||
.sort({ createdAt: -1 })
|
.sort({ createdAt: -1 })
|
||||||
.limit(5);
|
.limit(5);
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
await EEAuditLogService.createAuditLog(
|
||||||
req.authData,
|
req.authData,
|
||||||
{
|
{
|
||||||
@@ -138,39 +138,39 @@ export const createMIClientSecret = async (req: Request, res: Response) => {
|
|||||||
numUsesLimit
|
numUsesLimit
|
||||||
}
|
}
|
||||||
} = await validateRequest(reqValidator.CreateClientSecretV3, req);
|
} = await validateRequest(reqValidator.CreateClientSecretV3, req);
|
||||||
|
|
||||||
const machineMembershipOrg = await MachineMembershipOrg.findOne({
|
const machineMembershipOrg = await MachineMembershipOrg.findOne({
|
||||||
machineIdentity: new Types.ObjectId(machineId)
|
machineIdentity: new Types.ObjectId(machineId)
|
||||||
}).populate<{
|
}).populate<{
|
||||||
machineIdentity: IMachineIdentity,
|
machineIdentity: IMachineIdentity,
|
||||||
customRole: IRole
|
customRole: IRole
|
||||||
}>("machineIdentity customRole");
|
}>("machineIdentity customRole");
|
||||||
|
|
||||||
if (!machineMembershipOrg) throw ResourceNotFoundError();
|
if (!machineMembershipOrg) throw ResourceNotFoundError();
|
||||||
|
|
||||||
const { permission } = await getAuthDataOrgPermissions({
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
authData: req.authData,
|
authData: req.authData,
|
||||||
organizationId: machineMembershipOrg.organization
|
organizationId: machineMembershipOrg.organization
|
||||||
});
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.MachineIdentity
|
OrgPermissionSubjects.MachineIdentity
|
||||||
);
|
);
|
||||||
|
|
||||||
const rolePermission = await getOrgRolePermissions(
|
const rolePermission = await getOrgRolePermissions(
|
||||||
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
||||||
machineMembershipOrg.organization.toString()
|
machineMembershipOrg.organization.toString()
|
||||||
);
|
);
|
||||||
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
||||||
|
|
||||||
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
message: "Failed to create client secret for more privileged MI"
|
message: "Failed to create client secret for more privileged MI"
|
||||||
});
|
});
|
||||||
|
|
||||||
const clientSecret = crypto.randomBytes(32).toString("hex");
|
const clientSecret = crypto.randomBytes(32).toString("hex");
|
||||||
const clientSecretHash = await bcrypt.hash(clientSecret, await getSaltRounds());
|
const clientSecretHash = await bcrypt.hash(clientSecret, await getSaltRounds());
|
||||||
|
|
||||||
const machineIdentityClientSecret = await new MachineIdentityClientSecret({
|
const machineIdentityClientSecret = await new MachineIdentityClientSecret({
|
||||||
machineIdentity: machineMembershipOrg.machineIdentity,
|
machineIdentity: machineMembershipOrg.machineIdentity,
|
||||||
isActive: true,
|
isActive: true,
|
||||||
@@ -197,7 +197,7 @@ export const createMIClientSecret = async (req: Request, res: Response) => {
|
|||||||
organizationId: machineMembershipOrg.organization
|
organizationId: machineMembershipOrg.organization
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
clientSecret,
|
clientSecret,
|
||||||
clientSecretData: packageClientSecretData(machineIdentityClientSecret)
|
clientSecretData: packageClientSecretData(machineIdentityClientSecret)
|
||||||
@@ -221,11 +221,11 @@ export const deleteMIClientSecret = async (req: Request, res: Response) => {
|
|||||||
.findOne({
|
.findOne({
|
||||||
machineIdentity: new Types.ObjectId(machineId)
|
machineIdentity: new Types.ObjectId(machineId)
|
||||||
})
|
})
|
||||||
.populate<{
|
.populate<{
|
||||||
machineIdentity: IMachineIdentity,
|
machineIdentity: IMachineIdentity,
|
||||||
customRole: IRole
|
customRole: IRole
|
||||||
}>("machineIdentity customRole");
|
}>("machineIdentity customRole");
|
||||||
|
|
||||||
if (!machineMembershipOrg) throw ResourceNotFoundError({
|
if (!machineMembershipOrg) throw ResourceNotFoundError({
|
||||||
message: `Failed to find machine identity with id ${machineId}`
|
message: `Failed to find machine identity with id ${machineId}`
|
||||||
});
|
});
|
||||||
@@ -234,27 +234,27 @@ export const deleteMIClientSecret = async (req: Request, res: Response) => {
|
|||||||
authData: req.authData,
|
authData: req.authData,
|
||||||
organizationId: machineMembershipOrg.organization
|
organizationId: machineMembershipOrg.organization
|
||||||
});
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Delete,
|
OrgPermissionActions.Delete,
|
||||||
OrgPermissionSubjects.MachineIdentity
|
OrgPermissionSubjects.MachineIdentity
|
||||||
);
|
);
|
||||||
|
|
||||||
const rolePermission = await getOrgRolePermissions(
|
const rolePermission = await getOrgRolePermissions(
|
||||||
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
||||||
machineMembershipOrg.organization.toString()
|
machineMembershipOrg.organization.toString()
|
||||||
);
|
);
|
||||||
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
||||||
|
|
||||||
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
message: "Failed to delete client secrets for more privileged MI"
|
message: "Failed to delete client secrets for more privileged MI"
|
||||||
});
|
});
|
||||||
|
|
||||||
const machineIdentityClientSecret = await MachineIdentityClientSecret.findOneAndDelete({
|
const machineIdentityClientSecret = await MachineIdentityClientSecret.findOneAndDelete({
|
||||||
_id: clientSecretId,
|
_id: clientSecretId,
|
||||||
machineIdentity: machineId
|
machineIdentity: machineId
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!machineIdentityClientSecret) throw ResourceNotFoundError();
|
if (!machineIdentityClientSecret) throw ResourceNotFoundError();
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
await EEAuditLogService.createAuditLog(
|
||||||
@@ -290,14 +290,14 @@ export const loginMI = async (req: Request, res: Response) => {
|
|||||||
clientSecret
|
clientSecret
|
||||||
}
|
}
|
||||||
} = await validateRequest(reqValidator.LoginMachineIdentityV3, req);
|
} = await validateRequest(reqValidator.LoginMachineIdentityV3, req);
|
||||||
|
|
||||||
const machineIdentity = await MachineIdentity.findOne({
|
const machineIdentity = await MachineIdentity.findOne({
|
||||||
clientId,
|
clientId,
|
||||||
isActive: true
|
isActive: true
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!machineIdentity) throw UnauthorizedRequestError();
|
if (!machineIdentity) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
checkIPAgainstBlocklist({
|
checkIPAgainstBlocklist({
|
||||||
ipAddress: req.realIP,
|
ipAddress: req.realIP,
|
||||||
trustedIps: machineIdentity.clientSecretTrustedIps
|
trustedIps: machineIdentity.clientSecretTrustedIps
|
||||||
@@ -307,12 +307,12 @@ export const loginMI = async (req: Request, res: Response) => {
|
|||||||
machineIdentity: machineIdentity._id,
|
machineIdentity: machineIdentity._id,
|
||||||
isActive: true
|
isActive: true
|
||||||
});
|
});
|
||||||
|
|
||||||
let validatedClientSecretDatum: IMachineIdentityClientSecret | undefined;
|
let validatedClientSecretDatum: IMachineIdentityClientSecret | undefined;
|
||||||
|
|
||||||
for (const clientSecretDatum of clientSecretData) {
|
for (const clientSecretDatum of clientSecretData) {
|
||||||
const isSecretValid = await bcrypt.compare(
|
const isSecretValid = await bcrypt.compare(
|
||||||
clientSecret,
|
clientSecret,
|
||||||
clientSecretDatum.clientSecretHash
|
clientSecretDatum.clientSecretHash
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -321,9 +321,9 @@ export const loginMI = async (req: Request, res: Response) => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!validatedClientSecretDatum) throw UnauthorizedRequestError();
|
if (!validatedClientSecretDatum) throw UnauthorizedRequestError();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
clientSecretTTL,
|
clientSecretTTL,
|
||||||
clientSecretNumUses,
|
clientSecretNumUses,
|
||||||
@@ -331,22 +331,25 @@ export const loginMI = async (req: Request, res: Response) => {
|
|||||||
} = validatedClientSecretDatum;
|
} = validatedClientSecretDatum;
|
||||||
|
|
||||||
if (clientSecretTTL > 0) {
|
if (clientSecretTTL > 0) {
|
||||||
const expiresAt = new Date(new Date().getTime() + clientSecretTTL * 1000);
|
const clientSecretCreated = new Date(validatedClientSecretDatum.createdAt)
|
||||||
|
const ttlInMilliseconds = clientSecretTTL * 1000;
|
||||||
if (expiresAt < new Date()) {
|
const currentDate = new Date();
|
||||||
|
const expirationTime = new Date(clientSecretCreated.getTime() + ttlInMilliseconds);
|
||||||
|
|
||||||
|
if (currentDate > expirationTime) {
|
||||||
await MachineIdentityClientSecret.findByIdAndUpdate(
|
await MachineIdentityClientSecret.findByIdAndUpdate(
|
||||||
validatedClientSecretDatum._id,
|
validatedClientSecretDatum._id,
|
||||||
{
|
{
|
||||||
isActive: false
|
isActive: false
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
throw UnauthorizedRequestError({
|
throw UnauthorizedRequestError({
|
||||||
message: "Failed to authenticate MI credentials due to expired client secret"
|
message: "Failed to authenticate MI credentials due to expired client secret"
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientSecretNumUses > 0 && clientSecretNumUses === clientSecretNumUsesLimit) {
|
if (clientSecretNumUses > 0 && clientSecretNumUses === clientSecretNumUsesLimit) {
|
||||||
// number of times client secret can be used for
|
// number of times client secret can be used for
|
||||||
// a login operation reached
|
// a login operation reached
|
||||||
@@ -432,9 +435,9 @@ export const loginMI = async (req: Request, res: Response) => {
|
|||||||
*/
|
*/
|
||||||
export const createMachineIdentity = async (req: Request, res: Response) => {
|
export const createMachineIdentity = async (req: Request, res: Response) => {
|
||||||
const {
|
const {
|
||||||
body: {
|
body: {
|
||||||
name,
|
name,
|
||||||
organizationId,
|
organizationId,
|
||||||
role,
|
role,
|
||||||
clientSecretTrustedIps,
|
clientSecretTrustedIps,
|
||||||
accessTokenTrustedIps,
|
accessTokenTrustedIps,
|
||||||
@@ -446,7 +449,7 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
authData: req.authData,
|
authData: req.authData,
|
||||||
organizationId: new Types.ObjectId(organizationId)
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
});
|
});
|
||||||
|
|
||||||
ForbiddenError.from(permission).throwUnlessCan(
|
ForbiddenError.from(permission).throwUnlessCan(
|
||||||
OrgPermissionActions.Create,
|
OrgPermissionActions.Create,
|
||||||
OrgPermissionSubjects.MachineIdentity
|
OrgPermissionSubjects.MachineIdentity
|
||||||
@@ -454,7 +457,7 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
const rolePermission = await getOrgRolePermissions(role, organizationId);
|
const rolePermission = await getOrgRolePermissions(role, organizationId);
|
||||||
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
||||||
|
|
||||||
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
message: "Failed to create a more privileged MI"
|
message: "Failed to create a more privileged MI"
|
||||||
});
|
});
|
||||||
@@ -463,7 +466,7 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
if (!organization) throw BadRequestError({ message: `Organization with id ${organizationId} not found` });
|
if (!organization) throw BadRequestError({ message: `Organization with id ${organizationId} not found` });
|
||||||
|
|
||||||
const isCustomRole = ![ADMIN, MEMBER, NO_ACCESS].includes(role);
|
const isCustomRole = ![ADMIN, MEMBER, NO_ACCESS].includes(role);
|
||||||
|
|
||||||
let customRole;
|
let customRole;
|
||||||
if (isCustomRole) {
|
if (isCustomRole) {
|
||||||
customRole = await Role.findOne({
|
customRole = await Role.findOne({
|
||||||
@@ -471,12 +474,12 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
isOrgRole: true,
|
isOrgRole: true,
|
||||||
organization: new Types.ObjectId(organizationId)
|
organization: new Types.ObjectId(organizationId)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!customRole) throw BadRequestError({ message: "Role not found" });
|
if (!customRole) throw BadRequestError({ message: "Role not found" });
|
||||||
}
|
}
|
||||||
|
|
||||||
const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
|
const plan = await EELicenseService.getPlan(new Types.ObjectId(organizationId));
|
||||||
|
|
||||||
// validate trusted ips
|
// validate trusted ips
|
||||||
const reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => {
|
const reformattedClientSecretTrustedIps = clientSecretTrustedIps.map((clientSecretTrustedIp) => {
|
||||||
if (!plan.ipAllowlisting && clientSecretTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({
|
if (!plan.ipAllowlisting && clientSecretTrustedIp.ipAddress !== "0.0.0.0/0") return res.status(400).send({
|
||||||
@@ -484,11 +487,11 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const isValidIPOrCidr = isValidIpOrCidr(clientSecretTrustedIp.ipAddress);
|
const isValidIPOrCidr = isValidIpOrCidr(clientSecretTrustedIp.ipAddress);
|
||||||
|
|
||||||
if (!isValidIPOrCidr) return res.status(400).send({
|
if (!isValidIPOrCidr) return res.status(400).send({
|
||||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||||
});
|
});
|
||||||
|
|
||||||
return extractIPDetails(clientSecretTrustedIp.ipAddress);
|
return extractIPDetails(clientSecretTrustedIp.ipAddress);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -498,14 +501,14 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const isValidIPOrCidr = isValidIpOrCidr(accessTokenTrustedIp.ipAddress);
|
const isValidIPOrCidr = isValidIpOrCidr(accessTokenTrustedIp.ipAddress);
|
||||||
|
|
||||||
if (!isValidIPOrCidr) return res.status(400).send({
|
if (!isValidIPOrCidr) return res.status(400).send({
|
||||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||||
});
|
});
|
||||||
|
|
||||||
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
||||||
});
|
});
|
||||||
|
|
||||||
const isActive = true;
|
const isActive = true;
|
||||||
const machineIdentity = await new MachineIdentity({
|
const machineIdentity = await new MachineIdentity({
|
||||||
clientId: crypto.randomUUID(),
|
clientId: crypto.randomUUID(),
|
||||||
@@ -517,14 +520,14 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
clientSecretTrustedIps: reformattedClientSecretTrustedIps,
|
clientSecretTrustedIps: reformattedClientSecretTrustedIps,
|
||||||
accessTokenTrustedIps: reformattedAccessTokenTrustedIps,
|
accessTokenTrustedIps: reformattedAccessTokenTrustedIps,
|
||||||
}).save();
|
}).save();
|
||||||
|
|
||||||
await new MachineMembershipOrg({
|
await new MachineMembershipOrg({
|
||||||
machineIdentity: machineIdentity._id,
|
machineIdentity: machineIdentity._id,
|
||||||
organization: machineIdentity.organization,
|
organization: machineIdentity.organization,
|
||||||
role: isCustomRole ? CUSTOM : role,
|
role: isCustomRole ? CUSTOM : role,
|
||||||
customRole
|
customRole
|
||||||
}).save();
|
}).save();
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
await EEAuditLogService.createAuditLog(
|
||||||
req.authData,
|
req.authData,
|
||||||
{
|
{
|
||||||
@@ -541,7 +544,7 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
organizationId: new Types.ObjectId(organizationId)
|
organizationId: new Types.ObjectId(organizationId)
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
machineIdentity
|
machineIdentity
|
||||||
});
|
});
|
||||||
@@ -556,8 +559,8 @@ export const createMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
export const updateMachineIdentity = async (req: Request, res: Response) => {
|
export const updateMachineIdentity = async (req: Request, res: Response) => {
|
||||||
const {
|
const {
|
||||||
params: { machineId },
|
params: { machineId },
|
||||||
body: {
|
body: {
|
||||||
name,
|
name,
|
||||||
role,
|
role,
|
||||||
clientSecretTrustedIps,
|
clientSecretTrustedIps,
|
||||||
accessTokenTrustedIps,
|
accessTokenTrustedIps,
|
||||||
@@ -569,11 +572,11 @@ export const updateMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
.findOne({
|
.findOne({
|
||||||
machineIdentity: new Types.ObjectId(machineId)
|
machineIdentity: new Types.ObjectId(machineId)
|
||||||
})
|
})
|
||||||
.populate<{
|
.populate<{
|
||||||
machineIdentity: IMachineIdentity,
|
machineIdentity: IMachineIdentity,
|
||||||
customRole: IRole
|
customRole: IRole
|
||||||
}>("machineIdentity customRole");
|
}>("machineIdentity customRole");
|
||||||
|
|
||||||
if (!machineMembershipOrg) throw ResourceNotFoundError({
|
if (!machineMembershipOrg) throw ResourceNotFoundError({
|
||||||
message: `Failed to find machine identity with id ${machineId}`
|
message: `Failed to find machine identity with id ${machineId}`
|
||||||
});
|
});
|
||||||
@@ -588,18 +591,18 @@ export const updateMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const machineIdentityRolePermission = await getOrgRolePermissions(
|
const machineIdentityRolePermission = await getOrgRolePermissions(
|
||||||
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
||||||
machineMembershipOrg.organization.toString()
|
machineMembershipOrg.organization.toString()
|
||||||
);
|
);
|
||||||
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, machineIdentityRolePermission);
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, machineIdentityRolePermission);
|
||||||
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
message: "Failed to update more privileged MI"
|
message: "Failed to update more privileged MI"
|
||||||
});
|
});
|
||||||
|
|
||||||
if (role) {
|
if (role) {
|
||||||
const rolePermission = await getOrgRolePermissions(role, machineMembershipOrg.organization.toString());
|
const rolePermission = await getOrgRolePermissions(role, machineMembershipOrg.organization.toString());
|
||||||
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, rolePermission);
|
||||||
|
|
||||||
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
message: "Failed to update MI to a more privileged role"
|
message: "Failed to update MI to a more privileged role"
|
||||||
});
|
});
|
||||||
@@ -614,7 +617,7 @@ export const updateMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
isOrgRole: true,
|
isOrgRole: true,
|
||||||
organization: machineMembershipOrg.organization
|
organization: machineMembershipOrg.organization
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!customRole) throw BadRequestError({ message: "Role not found" });
|
if (!customRole) throw BadRequestError({ message: "Role not found" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -630,11 +633,11 @@ export const updateMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const isValidIPOrCidr = isValidIpOrCidr(clientSecretTrustedIp.ipAddress);
|
const isValidIPOrCidr = isValidIpOrCidr(clientSecretTrustedIp.ipAddress);
|
||||||
|
|
||||||
if (!isValidIPOrCidr) return res.status(400).send({
|
if (!isValidIPOrCidr) return res.status(400).send({
|
||||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||||
});
|
});
|
||||||
|
|
||||||
return extractIPDetails(clientSecretTrustedIp.ipAddress);
|
return extractIPDetails(clientSecretTrustedIp.ipAddress);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -648,15 +651,15 @@ export const updateMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const isValidIPOrCidr = isValidIpOrCidr(accessTokenTrustedIp.ipAddress);
|
const isValidIPOrCidr = isValidIpOrCidr(accessTokenTrustedIp.ipAddress);
|
||||||
|
|
||||||
if (!isValidIPOrCidr) return res.status(400).send({
|
if (!isValidIPOrCidr) return res.status(400).send({
|
||||||
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
message: "The IP is not a valid IPv4, IPv6, or CIDR block"
|
||||||
});
|
});
|
||||||
|
|
||||||
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
return extractIPDetails(accessTokenTrustedIp.ipAddress);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const machineIdentity = await MachineIdentity.findByIdAndUpdate(
|
const machineIdentity = await MachineIdentity.findByIdAndUpdate(
|
||||||
machineId,
|
machineId,
|
||||||
{
|
{
|
||||||
@@ -673,7 +676,7 @@ export const updateMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
if (!machineIdentity) throw BadRequestError({
|
if (!machineIdentity) throw BadRequestError({
|
||||||
message: `Failed to update machine identity with id ${machineId}`
|
message: `Failed to update machine identity with id ${machineId}`
|
||||||
});
|
});
|
||||||
|
|
||||||
await MachineMembershipOrg.findOneAndUpdate(
|
await MachineMembershipOrg.findOneAndUpdate(
|
||||||
{
|
{
|
||||||
machineIdentity: machineIdentity._id
|
machineIdentity: machineIdentity._id
|
||||||
@@ -681,7 +684,7 @@ export const updateMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
{
|
{
|
||||||
role: customRole ? CUSTOM : role,
|
role: customRole ? CUSTOM : role,
|
||||||
...(customRole ? {
|
...(customRole ? {
|
||||||
customRole
|
customRole
|
||||||
} : {}),
|
} : {}),
|
||||||
...(role && !customRole ? { // non-custom role
|
...(role && !customRole ? { // non-custom role
|
||||||
$unset: {
|
$unset: {
|
||||||
@@ -712,7 +715,7 @@ export const updateMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
machineIdentity
|
machineIdentity
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -725,20 +728,20 @@ export const deleteMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
const {
|
const {
|
||||||
params: { machineId }
|
params: { machineId }
|
||||||
} = await validateRequest(reqValidator.DeleteMachineIdentityV3, req);
|
} = await validateRequest(reqValidator.DeleteMachineIdentityV3, req);
|
||||||
|
|
||||||
const machineMembershipOrg = await MachineMembershipOrg
|
const machineMembershipOrg = await MachineMembershipOrg
|
||||||
.findOne({
|
.findOne({
|
||||||
machineIdentity: new Types.ObjectId(machineId)
|
machineIdentity: new Types.ObjectId(machineId)
|
||||||
})
|
})
|
||||||
.populate<{
|
.populate<{
|
||||||
machineIdentity: IMachineIdentity,
|
machineIdentity: IMachineIdentity,
|
||||||
customRole: IRole
|
customRole: IRole
|
||||||
}>("machineIdentity customRole");
|
}>("machineIdentity customRole");
|
||||||
|
|
||||||
if (!machineMembershipOrg) throw ResourceNotFoundError({
|
if (!machineMembershipOrg) throw ResourceNotFoundError({
|
||||||
message: `Failed to find machine identity with id ${machineId}`
|
message: `Failed to find machine identity with id ${machineId}`
|
||||||
});
|
});
|
||||||
|
|
||||||
const { permission } = await getAuthDataOrgPermissions({
|
const { permission } = await getAuthDataOrgPermissions({
|
||||||
authData: req.authData,
|
authData: req.authData,
|
||||||
organizationId: machineMembershipOrg.organization
|
organizationId: machineMembershipOrg.organization
|
||||||
@@ -749,33 +752,33 @@ export const deleteMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const machineIdentityRolePermission = await getOrgRolePermissions(
|
const machineIdentityRolePermission = await getOrgRolePermissions(
|
||||||
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
machineMembershipOrg?.customRole?.slug ?? machineMembershipOrg.role,
|
||||||
machineMembershipOrg.organization.toString()
|
machineMembershipOrg.organization.toString()
|
||||||
);
|
);
|
||||||
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, machineIdentityRolePermission);
|
const hasRequiredPrivileges = isAtLeastAsPrivilegedOrg(permission, machineIdentityRolePermission);
|
||||||
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
if (!hasRequiredPrivileges) throw ForbiddenRequestError({
|
||||||
message: "Failed to delete more privileged MI"
|
message: "Failed to delete more privileged MI"
|
||||||
});
|
});
|
||||||
|
|
||||||
const machineIdentity = await MachineIdentity.findByIdAndDelete(machineMembershipOrg.machineIdentity);
|
const machineIdentity = await MachineIdentity.findByIdAndDelete(machineMembershipOrg.machineIdentity);
|
||||||
if (!machineIdentity) throw ResourceNotFoundError({
|
if (!machineIdentity) throw ResourceNotFoundError({
|
||||||
message: `Machine identity with id ${machineId} not found`
|
message: `Machine identity with id ${machineId} not found`
|
||||||
});
|
});
|
||||||
|
|
||||||
await MachineMembershipOrg.findByIdAndDelete(machineMembershipOrg._id);
|
await MachineMembershipOrg.findByIdAndDelete(machineMembershipOrg._id);
|
||||||
|
|
||||||
if (!machineMembershipOrg) throw BadRequestError({
|
if (!machineMembershipOrg) throw BadRequestError({
|
||||||
message: `Failed to delete machine identity with id ${machineId}`
|
message: `Failed to delete machine identity with id ${machineId}`
|
||||||
});
|
});
|
||||||
|
|
||||||
await MachineMembership.deleteMany({
|
await MachineMembership.deleteMany({
|
||||||
machineIdentity: machineMembershipOrg.machineIdentity
|
machineIdentity: machineMembershipOrg.machineIdentity
|
||||||
});
|
});
|
||||||
|
|
||||||
await MachineIdentityClientSecret.deleteMany({
|
await MachineIdentityClientSecret.deleteMany({
|
||||||
machineIdentity: machineMembershipOrg.machineIdentity
|
machineIdentity: machineMembershipOrg.machineIdentity
|
||||||
});
|
});
|
||||||
|
|
||||||
await EEAuditLogService.createAuditLog(
|
await EEAuditLogService.createAuditLog(
|
||||||
req.authData,
|
req.authData,
|
||||||
{
|
{
|
||||||
@@ -795,5 +798,5 @@ export const deleteMachineIdentity = async (req: Request, res: Response) => {
|
|||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
machineIdentity
|
machineIdentity
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user