mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-14 07:30:20 +00:00
General improvements on auth templates
This commit is contained in:
@@ -7,10 +7,12 @@ export const TEMPLATE_VALIDATION_MESSAGES = {
|
||||
TEMPLATE_NAME_MAX_LENGTH: "Template name must be at most 64 characters long",
|
||||
AUTH_METHOD_REQUIRED: "Auth method is required",
|
||||
TEMPLATE_ID_REQUIRED: "Template ID is required",
|
||||
LDAP_URL_REQUIRED: "LDAP URL is required",
|
||||
BIND_DN_REQUIRED: "Bind DN is required",
|
||||
BIND_PASSWORD_REQUIRED: "Bind password is required",
|
||||
SEARCH_BASE_REQUIRED: "Search base is required"
|
||||
LDAP: {
|
||||
URL_REQUIRED: "LDAP URL is required",
|
||||
BIND_DN_REQUIRED: "Bind DN is required",
|
||||
BIND_PASSWORD_REQUIRED: "Bind password is required",
|
||||
SEARCH_BASE_REQUIRED: "Search base is required"
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const TEMPLATE_SUCCESS_MESSAGES = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ForbiddenError } from "@casl/ability";
|
||||
|
||||
import { EventType, TAuditLogServiceFactory } from "@app/ee/services/audit-log/audit-log-types";
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import {
|
||||
OrgPermissionMachineIdentityAuthTemplateActions,
|
||||
@@ -9,6 +10,7 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio
|
||||
import { BadRequestError, NotFoundError } from "@app/lib/errors";
|
||||
import { TOrgPermission } from "@app/lib/types";
|
||||
|
||||
import { ActorType } from "../auth/auth-type";
|
||||
import { TIdentityLdapAuthDALFactory } from "../identity-ldap-auth/identity-ldap-auth-dal";
|
||||
import { TKmsServiceFactory } from "../kms/kms-service";
|
||||
import { KmsDataKey } from "../kms/kms-types";
|
||||
@@ -30,6 +32,7 @@ type TIdentityAuthTemplateServiceFactoryDep = {
|
||||
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
|
||||
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey" | "encryptWithInputKey" | "decryptWithInputKey">;
|
||||
licenseService: Pick<TLicenseServiceFactory, "getPlan">;
|
||||
auditLogService: Pick<TAuditLogServiceFactory, "createAuditLog">;
|
||||
};
|
||||
|
||||
export type TIdentityAuthTemplateServiceFactory = ReturnType<typeof identityAuthTemplateServiceFactory>;
|
||||
@@ -39,7 +42,8 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
identityLdapAuthDAL,
|
||||
permissionService,
|
||||
kmsService,
|
||||
licenseService
|
||||
licenseService,
|
||||
auditLogService
|
||||
}: TIdentityAuthTemplateServiceFactoryDep) => {
|
||||
// Plan check
|
||||
const $checkPlan = async (orgId: string) => {
|
||||
@@ -87,7 +91,7 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
orgId: actorOrgId
|
||||
});
|
||||
|
||||
return template;
|
||||
return { ...template, templateFields };
|
||||
};
|
||||
|
||||
const updateTemplate = async ({
|
||||
@@ -104,7 +108,7 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
templateFields?: Record<string, unknown>;
|
||||
} & Omit<TOrgPermission, "orgId">) => {
|
||||
await $checkPlan(actorOrgId);
|
||||
const template = await identityAuthTemplateDAL.findById(templateId);
|
||||
const template = await identityAuthTemplateDAL.findByIdAndOrgId(templateId, actorOrgId);
|
||||
if (!template) {
|
||||
throw new NotFoundError({ message: "Template not found" });
|
||||
}
|
||||
@@ -126,6 +130,8 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
orgId: template.orgId
|
||||
});
|
||||
|
||||
let finalTemplateFields: Record<string, unknown> = {};
|
||||
|
||||
const updatedTemplate = await identityAuthTemplateDAL.transaction(async (tx) => {
|
||||
const authTemplate = await identityAuthTemplateDAL.updateById(
|
||||
templateId,
|
||||
@@ -149,12 +155,13 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
) as TLdapTemplateFields;
|
||||
|
||||
const mergedTemplateFields: TLdapTemplateFields = { ...currentTemplateFields, ...templateFields };
|
||||
|
||||
finalTemplateFields = mergedTemplateFields;
|
||||
const ldapUpdateData: {
|
||||
url?: string;
|
||||
searchBase?: string;
|
||||
encryptedBindDN?: Buffer;
|
||||
encryptedBindPass?: Buffer;
|
||||
encryptedLdapCaCertificate?: Buffer;
|
||||
} = {};
|
||||
|
||||
if ("url" in templateFields) {
|
||||
@@ -173,16 +180,38 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
plainText: Buffer.from(mergedTemplateFields.bindPass)
|
||||
}).cipherTextBlob;
|
||||
}
|
||||
if ("ldapCaCertificate" in templateFields) {
|
||||
ldapUpdateData.encryptedLdapCaCertificate = encryptor({
|
||||
plainText: Buffer.from(mergedTemplateFields.ldapCaCertificate || "")
|
||||
}).cipherTextBlob;
|
||||
}
|
||||
|
||||
if (Object.keys(ldapUpdateData).length > 0) {
|
||||
await identityLdapAuthDAL.update({ templateId }, ldapUpdateData, tx);
|
||||
const updatedLdapAuths = await identityLdapAuthDAL.update({ templateId }, ldapUpdateData, tx);
|
||||
await Promise.all(
|
||||
updatedLdapAuths.map(async (updatedLdapAuth) => {
|
||||
await auditLogService.createAuditLog({
|
||||
actor: {
|
||||
type: ActorType.PLATFORM,
|
||||
metadata: {}
|
||||
},
|
||||
orgId: actorOrgId,
|
||||
event: {
|
||||
type: EventType.UPDATE_IDENTITY_LDAP_AUTH,
|
||||
metadata: {
|
||||
identityId: updatedLdapAuth.identityId,
|
||||
templateId: template.id
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return authTemplate;
|
||||
});
|
||||
|
||||
return updatedTemplate;
|
||||
return { ...updatedTemplate, templateFields: finalTemplateFields };
|
||||
};
|
||||
|
||||
const deleteTemplate = async ({
|
||||
@@ -193,7 +222,7 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
actorOrgId
|
||||
}: TDeleteIdentityAuthTemplateDTO) => {
|
||||
await $checkPlan(actorOrgId);
|
||||
const template = await identityAuthTemplateDAL.findById(templateId);
|
||||
const template = await identityAuthTemplateDAL.findByIdAndOrgId(templateId, actorOrgId);
|
||||
if (!template) {
|
||||
throw new NotFoundError({ message: "Template not found" });
|
||||
}
|
||||
@@ -212,7 +241,25 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
|
||||
const deletedTemplate = await identityAuthTemplateDAL.transaction(async (tx) => {
|
||||
// Remove template reference from identityLdapAuth records
|
||||
await identityLdapAuthDAL.update({ templateId }, { templateId: null }, tx);
|
||||
const updatedLdapAuths = await identityLdapAuthDAL.update({ templateId }, { templateId: null }, tx);
|
||||
await Promise.all(
|
||||
updatedLdapAuths.map(async (updatedLdapAuth) => {
|
||||
await auditLogService.createAuditLog({
|
||||
actor: {
|
||||
type: ActorType.PLATFORM,
|
||||
metadata: {}
|
||||
},
|
||||
orgId: actorOrgId,
|
||||
event: {
|
||||
type: EventType.UPDATE_IDENTITY_LDAP_AUTH,
|
||||
metadata: {
|
||||
identityId: updatedLdapAuth.identityId,
|
||||
templateId: template.id
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
// Delete the template
|
||||
const [deletedTpl] = await identityAuthTemplateDAL.delete({ id: templateId }, tx);
|
||||
@@ -230,7 +277,7 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
actorOrgId
|
||||
}: TGetIdentityAuthTemplateDTO) => {
|
||||
await $checkPlan(actorOrgId);
|
||||
const template = await identityAuthTemplateDAL.findById(templateId);
|
||||
const template = await identityAuthTemplateDAL.findByIdAndOrgId(templateId, actorOrgId);
|
||||
if (!template) {
|
||||
throw new NotFoundError({ message: "Template not found" });
|
||||
}
|
||||
@@ -313,7 +360,7 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates,
|
||||
OrgPermissionMachineIdentityAuthTemplateActions.UseTemplates,
|
||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||
);
|
||||
|
||||
@@ -350,7 +397,7 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||
);
|
||||
|
||||
const template = await identityAuthTemplateDAL.findById(templateId);
|
||||
const template = await identityAuthTemplateDAL.findByIdAndOrgId(templateId, actorOrgId);
|
||||
if (!template) {
|
||||
throw new NotFoundError({ message: "Template not found" });
|
||||
}
|
||||
@@ -376,11 +423,11 @@ export const identityAuthTemplateServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionMachineIdentityAuthTemplateActions.ListTemplates,
|
||||
OrgPermissionMachineIdentityAuthTemplateActions.UnlinkTemplates,
|
||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||
);
|
||||
|
||||
const template = await identityAuthTemplateDAL.findById(templateId);
|
||||
const template = await identityAuthTemplateDAL.findByIdAndOrgId(templateId, actorOrgId);
|
||||
if (!template) {
|
||||
throw new NotFoundError({ message: "Template not found" });
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export type TLdapTemplateFields = {
|
||||
bindDN: string;
|
||||
bindPass: string;
|
||||
searchBase: string;
|
||||
ldapCaCertificate?: string;
|
||||
};
|
||||
|
||||
// Union type for all template field types
|
||||
|
||||
@@ -4,7 +4,11 @@ import { ForbiddenError } from "@casl/ability";
|
||||
import { IdentityAuthMethod } from "@app/db/schemas";
|
||||
import { testLDAPConfig } from "@app/ee/services/ldap-config/ldap-fns";
|
||||
import { TLicenseServiceFactory } from "@app/ee/services/license/license-service";
|
||||
import { OrgPermissionIdentityActions, OrgPermissionSubjects } from "@app/ee/services/permission/org-permission";
|
||||
import {
|
||||
OrgPermissionIdentityActions,
|
||||
OrgPermissionMachineIdentityAuthTemplateActions,
|
||||
OrgPermissionSubjects
|
||||
} from "@app/ee/services/permission/org-permission";
|
||||
import {
|
||||
constructPermissionErrorMessage,
|
||||
validatePrivilegeChangeOperation
|
||||
@@ -217,6 +221,14 @@ export const identityLdapAuthServiceFactory = ({
|
||||
actorOrgId
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Create, OrgPermissionSubjects.Identity);
|
||||
|
||||
if (templateId) {
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionMachineIdentityAuthTemplateActions.UseTemplates,
|
||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||
);
|
||||
}
|
||||
|
||||
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
|
||||
|
||||
if (!plan.ldap) {
|
||||
@@ -254,7 +266,7 @@ export const identityLdapAuthServiceFactory = ({
|
||||
? await identityAuthTemplateDAL.findByIdAndOrgId(templateId, identityMembershipOrg.orgId)
|
||||
: undefined;
|
||||
|
||||
let ldapConfig: { bindDN: string; bindPass: string; searchBase: string; url: string };
|
||||
let ldapConfig: { bindDN: string; bindPass: string; searchBase: string; url: string; ldapCaCertificate?: string };
|
||||
if (template) {
|
||||
ldapConfig = JSON.parse(decryptor({ cipherTextBlob: template.templateFields }).toString());
|
||||
} else {
|
||||
@@ -267,7 +279,8 @@ export const identityLdapAuthServiceFactory = ({
|
||||
bindDN,
|
||||
bindPass,
|
||||
searchBase,
|
||||
url
|
||||
url,
|
||||
ldapCaCertificate
|
||||
};
|
||||
}
|
||||
|
||||
@@ -280,9 +293,9 @@ export const identityLdapAuthServiceFactory = ({
|
||||
});
|
||||
|
||||
let encryptedLdapCaCertificate: Buffer | undefined;
|
||||
if (ldapCaCertificate) {
|
||||
if (ldapConfig.ldapCaCertificate) {
|
||||
const { cipherTextBlob: encryptedCertificate } = encryptor({
|
||||
plainText: Buffer.from(ldapCaCertificate)
|
||||
plainText: Buffer.from(ldapConfig.ldapCaCertificate)
|
||||
});
|
||||
|
||||
encryptedLdapCaCertificate = encryptedCertificate;
|
||||
@@ -291,7 +304,7 @@ export const identityLdapAuthServiceFactory = ({
|
||||
const isConnected = await testLDAPConfig({
|
||||
bindDN: ldapConfig.bindDN,
|
||||
bindPass: ldapConfig.bindPass,
|
||||
caCert: ldapCaCertificate || "",
|
||||
caCert: ldapConfig.ldapCaCertificate || "",
|
||||
url: ldapConfig.url
|
||||
});
|
||||
|
||||
@@ -371,6 +384,13 @@ export const identityLdapAuthServiceFactory = ({
|
||||
);
|
||||
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Edit, OrgPermissionSubjects.Identity);
|
||||
|
||||
if (templateId) {
|
||||
ForbiddenError.from(permission).throwUnlessCan(
|
||||
OrgPermissionMachineIdentityAuthTemplateActions.UseTemplates,
|
||||
OrgPermissionSubjects.MachineIdentityAuthTemplate
|
||||
);
|
||||
}
|
||||
|
||||
const plan = await licenseService.getPlan(identityMembershipOrg.orgId);
|
||||
|
||||
if (!plan.ldap) {
|
||||
@@ -411,6 +431,7 @@ export const identityLdapAuthServiceFactory = ({
|
||||
bindPass?: string;
|
||||
searchBase?: string;
|
||||
url?: string;
|
||||
ldapCaCertificate?: string;
|
||||
};
|
||||
|
||||
if (template) {
|
||||
@@ -420,7 +441,8 @@ export const identityLdapAuthServiceFactory = ({
|
||||
bindDN,
|
||||
bindPass,
|
||||
searchBase,
|
||||
url
|
||||
url,
|
||||
ldapCaCertificate
|
||||
};
|
||||
}
|
||||
|
||||
@@ -434,9 +456,9 @@ export const identityLdapAuthServiceFactory = ({
|
||||
}
|
||||
|
||||
let encryptedLdapCaCertificate: Buffer | undefined;
|
||||
if (ldapCaCertificate) {
|
||||
if (config.ldapCaCertificate) {
|
||||
const { cipherTextBlob: ldapCaCertificateCiphertext } = encryptor({
|
||||
plainText: Buffer.from(ldapCaCertificate)
|
||||
plainText: Buffer.from(config.ldapCaCertificate)
|
||||
});
|
||||
|
||||
encryptedLdapCaCertificate = ldapCaCertificateCiphertext;
|
||||
@@ -456,7 +478,7 @@ export const identityLdapAuthServiceFactory = ({
|
||||
const isConnected = await testLDAPConfig({
|
||||
bindDN: config.bindDN || ldapConfig.bindDN,
|
||||
bindPass: config.bindPass || ldapConfig.bindPass,
|
||||
caCert: ldapCaCertificate || ldapConfig.caCert,
|
||||
caCert: config.ldapCaCertificate || ldapConfig.caCert,
|
||||
url: config.url || ldapConfig.url
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user