diff --git a/backend/src/@types/knex.d.ts b/backend/src/@types/knex.d.ts index d8c1a2ede..f689f3357 100644 --- a/backend/src/@types/knex.d.ts +++ b/backend/src/@types/knex.d.ts @@ -53,6 +53,9 @@ import { TCertificateSecretsUpdate, TCertificatesInsert, TCertificatesUpdate, + TCertificateTemplateEstConfigs, + TCertificateTemplateEstConfigsInsert, + TCertificateTemplateEstConfigsUpdate, TCertificateTemplates, TCertificateTemplatesInsert, TCertificateTemplatesUpdate, @@ -321,11 +324,6 @@ import { TWebhooksInsert, TWebhooksUpdate } from "@app/db/schemas"; -import { - TCertificateAuthorityEstConfigs, - TCertificateAuthorityEstConfigsInsert, - TCertificateAuthorityEstConfigsUpdate -} from "@app/db/schemas/certificate-authority-est-configs"; import { TSecretV2TagJunction, TSecretV2TagJunctionInsert, @@ -377,6 +375,11 @@ declare module "knex/types/tables" { TCertificateTemplatesInsert, TCertificateTemplatesUpdate >; + [TableName.CertificateTemplateEstConfig]: KnexOriginal.CompositeTableType< + TCertificateTemplateEstConfigs, + TCertificateTemplateEstConfigsInsert, + TCertificateTemplateEstConfigsUpdate + >; [TableName.CertificateBody]: KnexOriginal.CompositeTableType< TCertificateBodies, TCertificateBodiesInsert, @@ -387,11 +390,6 @@ declare module "knex/types/tables" { TCertificateSecretsInsert, TCertificateSecretsUpdate >; - [TableName.CertificateAuthorityEstConfig]: KnexOriginal.CompositeTableType< - TCertificateAuthorityEstConfigs, - TCertificateAuthorityEstConfigsInsert, - TCertificateAuthorityEstConfigsUpdate - >; [TableName.PkiAlert]: KnexOriginal.CompositeTableType; [TableName.PkiCollection]: KnexOriginal.CompositeTableType< TPkiCollections, diff --git a/backend/src/db/migrations/20240813141341_certificate-authority-est-configuration.ts b/backend/src/db/migrations/20240819092916_certificate-template-est-configuration.ts similarity index 53% rename from backend/src/db/migrations/20240813141341_certificate-authority-est-configuration.ts rename to backend/src/db/migrations/20240819092916_certificate-template-est-configuration.ts index db0164d3e..4aaff2c8c 100644 --- a/backend/src/db/migrations/20240813141341_certificate-authority-est-configuration.ts +++ b/backend/src/db/migrations/20240819092916_certificate-template-est-configuration.ts @@ -4,23 +4,23 @@ import { TableName } from "../schemas"; import { createOnUpdateTrigger, dropOnUpdateTrigger } from "../utils"; export async function up(knex: Knex): Promise { - const hasEstConfigTable = await knex.schema.hasTable(TableName.CertificateAuthorityEstConfig); + const hasEstConfigTable = await knex.schema.hasTable(TableName.CertificateTemplateEstConfig); if (!hasEstConfigTable) { - await knex.schema.createTable(TableName.CertificateAuthorityEstConfig, (tb) => { + await knex.schema.createTable(TableName.CertificateTemplateEstConfig, (tb) => { tb.uuid("id", { primaryKey: true }).defaultTo(knex.fn.uuid()); - tb.uuid("caId").notNullable().unique(); - tb.foreign("caId").references("id").inTable(TableName.CertificateAuthority).onDelete("CASCADE"); + tb.uuid("certificateTemplateId").notNullable().unique(); + tb.foreign("certificateTemplateId").references("id").inTable(TableName.CertificateTemplate).onDelete("CASCADE"); tb.binary("encryptedCaChain").notNullable(); tb.string("hashedPassphrase").notNullable(); tb.boolean("isEnabled"); tb.timestamps(true, true, true); }); - await createOnUpdateTrigger(knex, TableName.CertificateAuthorityEstConfig); + await createOnUpdateTrigger(knex, TableName.CertificateTemplateEstConfig); } } export async function down(knex: Knex): Promise { - await knex.schema.dropTableIfExists(TableName.CertificateAuthorityEstConfig); - await dropOnUpdateTrigger(knex, TableName.CertificateAuthorityEstConfig); + await knex.schema.dropTableIfExists(TableName.CertificateTemplateEstConfig); + await dropOnUpdateTrigger(knex, TableName.CertificateTemplateEstConfig); } diff --git a/backend/src/db/schemas/certificate-authority-est-configs.ts b/backend/src/db/schemas/certificate-template-est-configs.ts similarity index 52% rename from backend/src/db/schemas/certificate-authority-est-configs.ts rename to backend/src/db/schemas/certificate-template-est-configs.ts index 43ef5d25f..8e785ff38 100644 --- a/backend/src/db/schemas/certificate-authority-est-configs.ts +++ b/backend/src/db/schemas/certificate-template-est-configs.ts @@ -9,9 +9,9 @@ import { zodBuffer } from "@app/lib/zod"; import { TImmutableDBKeys } from "./models"; -export const CertificateAuthorityEstConfigsSchema = z.object({ +export const CertificateTemplateEstConfigsSchema = z.object({ id: z.string().uuid(), - caId: z.string().uuid(), + certificateTemplateId: z.string().uuid(), encryptedCaChain: zodBuffer, hashedPassphrase: z.string(), isEnabled: z.boolean().nullable().optional(), @@ -19,11 +19,11 @@ export const CertificateAuthorityEstConfigsSchema = z.object({ updatedAt: z.date() }); -export type TCertificateAuthorityEstConfigs = z.infer; -export type TCertificateAuthorityEstConfigsInsert = Omit< - z.input, +export type TCertificateTemplateEstConfigs = z.infer; +export type TCertificateTemplateEstConfigsInsert = Omit< + z.input, TImmutableDBKeys >; -export type TCertificateAuthorityEstConfigsUpdate = Partial< - Omit, TImmutableDBKeys> +export type TCertificateTemplateEstConfigsUpdate = Partial< + Omit, TImmutableDBKeys> >; diff --git a/backend/src/db/schemas/index.ts b/backend/src/db/schemas/index.ts index bfa3a0a0e..2a089df2b 100644 --- a/backend/src/db/schemas/index.ts +++ b/backend/src/db/schemas/index.ts @@ -14,6 +14,7 @@ export * from "./certificate-authority-crl"; export * from "./certificate-authority-secret"; export * from "./certificate-bodies"; export * from "./certificate-secrets"; +export * from "./certificate-template-est-configs"; export * from "./certificate-templates"; export * from "./certificates"; export * from "./dynamic-secret-leases"; diff --git a/backend/src/db/schemas/models.ts b/backend/src/db/schemas/models.ts index f8c68e671..ba9dfcae1 100644 --- a/backend/src/db/schemas/models.ts +++ b/backend/src/db/schemas/models.ts @@ -3,7 +3,7 @@ import { z } from "zod"; export enum TableName { Users = "users", CertificateAuthority = "certificate_authorities", - CertificateAuthorityEstConfig = "certificate_authority_est_configs", + CertificateTemplateEstConfig = "certificate_template_est_configs", CertificateAuthorityCert = "certificate_authority_certs", CertificateAuthoritySecret = "certificate_authority_secret", CertificateAuthorityCrl = "certificate_authority_crl", diff --git a/backend/src/server/routes/est/certificate-est-router.ts b/backend/src/server/routes/est/certificate-est-router.ts index fdbc3babe..00ead7836 100644 --- a/backend/src/server/routes/est/certificate-est-router.ts +++ b/backend/src/server/routes/est/certificate-est-router.ts @@ -39,13 +39,13 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) = } const urlFragments = req.url.split("/"); - const certificateAuthorityId = urlFragments.slice(-2)[0]; - const caEstConfig = await server.services.certificateAuthority.getCaEstConfiguration({ + const certificateTemplateId = urlFragments.slice(-2)[0]; + const estConfig = await server.services.certificateTemplate.getEstConfiguration({ isInternal: true, - caId: certificateAuthorityId + certificateTemplateId }); - if (!caEstConfig.isEnabled) { + if (!estConfig.isEnabled) { throw new BadRequestError({ message: "EST enrollment is disabled" }); @@ -68,7 +68,7 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) = .trim(); // validate SSL client cert against configured CA - const chainCerts = caEstConfig.caChain + const chainCerts = estConfig.caChain .match(/-----BEGIN CERTIFICATE-----[\s\S]+?-----END CERTIFICATE-----/g) ?.map((cert) => { const processedBody = cert @@ -122,7 +122,7 @@ export const registerCertificateEstRouter = async (server: FastifyZodProvider) = }); } - const isPasswordValid = await bcrypt.compare(password, caEstConfig.hashedPassphrase); + const isPasswordValid = await bcrypt.compare(password, estConfig.hashedPassphrase); if (!isPasswordValid) { throw new UnauthorizedError({ message: "Invalid credentials" diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index d5735ff9f..edef022b8 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -86,11 +86,11 @@ import { certificateDALFactory } from "@app/services/certificate/certificate-dal import { certificateServiceFactory } from "@app/services/certificate/certificate-service"; import { certificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal"; import { certificateAuthorityDALFactory } from "@app/services/certificate-authority/certificate-authority-dal"; -import { certificateAuthorityEstConfigDALFactory } from "@app/services/certificate-authority/certificate-authority-est-config-dal"; import { certificateAuthorityQueueFactory } from "@app/services/certificate-authority/certificate-authority-queue"; import { certificateAuthoritySecretDALFactory } from "@app/services/certificate-authority/certificate-authority-secret-dal"; import { certificateAuthorityServiceFactory } from "@app/services/certificate-authority/certificate-authority-service"; import { certificateTemplateDALFactory } from "@app/services/certificate-template/certificate-template-dal"; +import { certificateTemplateEstConfigDALFactory } from "@app/services/certificate-template/certificate-template-est-config-dal"; import { certificateTemplateServiceFactory } from "@app/services/certificate-template/certificate-template-service"; import { groupProjectDALFactory } from "@app/services/group-project/group-project-dal"; import { groupProjectMembershipRoleDALFactory } from "@app/services/group-project/group-project-membership-role-dal"; @@ -591,8 +591,8 @@ export const registerRoutes = async ( const certificateAuthorityCertDAL = certificateAuthorityCertDALFactory(db); const certificateAuthoritySecretDAL = certificateAuthoritySecretDALFactory(db); const certificateAuthorityCrlDAL = certificateAuthorityCrlDALFactory(db); - const certificateAuthorityEstConfigDAL = certificateAuthorityEstConfigDALFactory(db); const certificateTemplateDAL = certificateTemplateDALFactory(db); + const certificateTemplateEstConfigDAL = certificateTemplateEstConfigDALFactory(db); const certificateDAL = certificateDALFactory(db); const certificateBodyDAL = certificateBodyDALFactory(db); @@ -636,8 +636,7 @@ export const registerRoutes = async ( pkiCollectionItemDAL, projectDAL, kmsService, - permissionService, - certificateAuthorityEstConfigDAL + permissionService }); const certificateAuthorityCrlService = certificateAuthorityCrlServiceFactory({ @@ -651,8 +650,11 @@ export const registerRoutes = async ( const certificateTemplateService = certificateTemplateServiceFactory({ certificateTemplateDAL, + certificateTemplateEstConfigDAL, certificateAuthorityDAL, - permissionService + permissionService, + kmsService, + projectDAL }); const pkiAlertService = pkiAlertServiceFactory({ diff --git a/backend/src/server/routes/v1/certificate-authority-router.ts b/backend/src/server/routes/v1/certificate-authority-router.ts index 896dbf18e..d009fc624 100644 --- a/backend/src/server/routes/v1/certificate-authority-router.ts +++ b/backend/src/server/routes/v1/certificate-authority-router.ts @@ -2,7 +2,6 @@ import ms from "ms"; import { z } from "zod"; import { CertificateAuthoritiesSchema } from "@app/db/schemas"; -import { CertificateAuthorityEstConfigsSchema } from "@app/db/schemas/certificate-authority-est-configs"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { CERTIFICATE_AUTHORITIES } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -700,129 +699,4 @@ export const registerCaRouter = async (server: FastifyZodProvider) => { }; } }); - - server.route({ - method: "POST", - url: "/:caId/est-config", - config: { - rateLimit: writeLimit - }, - onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), - schema: { - description: "Create CA EST configuration", - params: z.object({ - caId: z.string().trim() - }), - body: z.object({ - caChain: z.string().trim().min(1), - passphrase: z.string().min(1), - isEnabled: z.boolean().default(true) - }), - response: { - 200: z.object({ - caEstConfig: CertificateAuthorityEstConfigsSchema.pick({ - caId: true, - isEnabled: true - }) - }) - } - }, - handler: async (req) => { - const caEstConfig = await server.services.certificateAuthority.createCaEstConfiguration({ - caId: req.params.caId, - actor: req.permission.type, - actorId: req.permission.id, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - ...req.body - }); - - return { - caEstConfig - }; - } - }); - - server.route({ - method: "PATCH", - url: "/:caId/est-config", - config: { - rateLimit: writeLimit - }, - onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), - schema: { - description: "Update CA EST configuration", - params: z.object({ - caId: z.string().trim() - }), - body: z.object({ - caChain: z.string().trim().min(1).optional(), - passphrase: z.string().min(1).optional(), - isEnabled: z.boolean().optional() - }), - response: { - 200: z.object({ - caEstConfig: CertificateAuthorityEstConfigsSchema.pick({ - caId: true, - isEnabled: true - }) - }) - } - }, - handler: async (req) => { - const caEstConfig = await server.services.certificateAuthority.updateCaEstConfiguration({ - caId: req.params.caId, - actor: req.permission.type, - actorId: req.permission.id, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId, - ...req.body - }); - - return { - caEstConfig - }; - } - }); - - server.route({ - method: "GET", - url: "/:caId/est-config", - config: { - rateLimit: readLimit - }, - onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), - schema: { - description: "Get CA EST configuration", - params: z.object({ - caId: z.string().trim() - }), - response: { - 200: z.object({ - caEstConfig: CertificateAuthorityEstConfigsSchema.pick({ - caId: true, - isEnabled: true - }).merge( - z.object({ - caChain: z.string() - }) - ) - }) - } - }, - handler: async (req) => { - const caEstConfig = await server.services.certificateAuthority.getCaEstConfiguration({ - isInternal: false, - caId: req.params.caId, - actor: req.permission.type, - actorId: req.permission.id, - actorAuthMethod: req.permission.authMethod, - actorOrgId: req.permission.orgId - }); - - return { - caEstConfig - }; - } - }); }; diff --git a/backend/src/server/routes/v1/certificate-template-router.ts b/backend/src/server/routes/v1/certificate-template-router.ts index 3f3ecd5b3..786f3bdae 100644 --- a/backend/src/server/routes/v1/certificate-template-router.ts +++ b/backend/src/server/routes/v1/certificate-template-router.ts @@ -1,6 +1,7 @@ import ms from "ms"; import { z } from "zod"; +import { CertificateTemplateEstConfigsSchema } from "@app/db/schemas"; import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { CERTIFICATE_TEMPLATES } from "@app/lib/api-docs"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -9,6 +10,12 @@ import { AuthMode } from "@app/services/auth/auth-type"; import { sanitizedCertificateTemplate } from "@app/services/certificate-template/certificate-template-schema"; import { validateTemplateRegexField } from "@app/services/certificate-template/certificate-template-validators"; +const sanitizedEstConfig = CertificateTemplateEstConfigsSchema.pick({ + id: true, + certificateTemplateId: true, + isEnabled: true +}); + export const registerCertificateTemplateRouter = async (server: FastifyZodProvider) => { server.route({ method: "GET", @@ -202,4 +209,106 @@ export const registerCertificateTemplateRouter = async (server: FastifyZodProvid return certificateTemplate; } }); + + server.route({ + method: "POST", + url: "/:certificateTemplateId/est-config", + config: { + rateLimit: writeLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Create Certificate Template EST configuration", + params: z.object({ + certificateTemplateId: z.string().trim() + }), + body: z.object({ + caChain: z.string().trim().min(1), + passphrase: z.string().min(1), + isEnabled: z.boolean().default(true) + }), + response: { + 200: sanitizedEstConfig + } + }, + handler: async (req) => { + const estConfig = await server.services.certificateTemplate.createEstConfiguration({ + certificateTemplateId: req.params.certificateTemplateId, + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.body + }); + + return estConfig; + } + }); + + server.route({ + method: "PATCH", + url: "/:certificateTemplateId/est-config", + config: { + rateLimit: writeLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Update Certificate Template EST configuration", + params: z.object({ + certificateTemplateId: z.string().trim() + }), + body: z.object({ + caChain: z.string().trim().min(1).optional(), + passphrase: z.string().min(1).optional(), + isEnabled: z.boolean().optional() + }), + response: { + 200: sanitizedEstConfig + } + }, + handler: async (req) => { + const estConfig = await server.services.certificateTemplate.updateEstConfiguration({ + certificateTemplateId: req.params.certificateTemplateId, + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId, + ...req.body + }); + + return estConfig; + } + }); + + server.route({ + method: "GET", + url: "/:certificateTemplateId/est-config", + config: { + rateLimit: readLimit + }, + onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), + schema: { + description: "Get Certificate Template EST configuration", + params: z.object({ + certificateTemplateId: z.string().trim() + }), + response: { + 200: sanitizedEstConfig.extend({ + caChain: z.string() + }) + } + }, + handler: async (req) => { + const estConfig = await server.services.certificateTemplate.getEstConfiguration({ + isInternal: false, + certificateTemplateId: req.params.certificateTemplateId, + actor: req.permission.type, + actorId: req.permission.id, + actorAuthMethod: req.permission.authMethod, + actorOrgId: req.permission.orgId + }); + + return estConfig; + } + }); }; diff --git a/backend/src/services/certificate-authority/certificate-authority-est-config-dal.ts b/backend/src/services/certificate-authority/certificate-authority-est-config-dal.ts deleted file mode 100644 index 7043a399d..000000000 --- a/backend/src/services/certificate-authority/certificate-authority-est-config-dal.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { TDbClient } from "@app/db"; -import { TableName } from "@app/db/schemas"; -import { ormify } from "@app/lib/knex"; - -export type TCertificateAuthorityEstConfigDALFactory = ReturnType; - -export const certificateAuthorityEstConfigDALFactory = (db: TDbClient) => { - const caEstConfigOrm = ormify(db, TableName.CertificateAuthorityEstConfig); - - return caEstConfigOrm; -}; diff --git a/backend/src/services/certificate-authority/certificate-authority-service.ts b/backend/src/services/certificate-authority/certificate-authority-service.ts index ddbade5f5..1cdd11238 100644 --- a/backend/src/services/certificate-authority/certificate-authority-service.ts +++ b/backend/src/services/certificate-authority/certificate-authority-service.ts @@ -1,16 +1,13 @@ /* eslint-disable no-bitwise */ import { ForbiddenError } from "@casl/ability"; import * as x509 from "@peculiar/x509"; -import bcrypt from "bcrypt"; import crypto, { KeyObject } from "crypto"; import ms from "ms"; import { z } from "zod"; import { TCertificateAuthorities, TCertificateTemplates } from "@app/db/schemas"; -import { TCertificateAuthorityEstConfigsUpdate } from "@app/db/schemas/certificate-authority-est-configs"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; -import { getConfig } from "@app/lib/config/env"; import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal"; import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal"; @@ -26,7 +23,6 @@ import { TCertificateTemplateDALFactory } from "../certificate-template/certific import { validateCertificateDetailsAgainstTemplate } from "../certificate-template/certificate-template-fns"; import { TCertificateAuthorityCertDALFactory } from "./certificate-authority-cert-dal"; import { TCertificateAuthorityDALFactory } from "./certificate-authority-dal"; -import { TCertificateAuthorityEstConfigDALFactory } from "./certificate-authority-est-config-dal"; import { createDistinguishedName, getCaCertChain, // TODO: consider rename @@ -41,20 +37,17 @@ import { CaStatus, CaType, TCreateCaDTO, - TCreateCaEstConfigurationDTO, TDeleteCaDTO, TGetCaCertDTO, TGetCaCertsDTO, TGetCaCsrDTO, TGetCaDTO, - TGetCaEstConfigurationDTO, TImportCertToCaDTO, TIssueCertFromCaDTO, TRenewCaCertDTO, TSignCertFromCaDTO, TSignIntermediateDTO, - TUpdateCaDTO, - TUpdateCaEstConfigurationDTO + TUpdateCaDTO } from "./certificate-authority-types"; import { hostnameRegex } from "./certificate-authority-validators"; @@ -71,7 +64,6 @@ type TCertificateAuthorityServiceFactoryDep = { certificateAuthorityCrlDAL: Pick; certificateTemplateDAL: Pick; certificateAuthorityQueue: TCertificateAuthorityQueueFactory; // TODO: Pick - certificateAuthorityEstConfigDAL: Pick; certificateDAL: Pick; certificateBodyDAL: Pick; pkiCollectionDAL: Pick; @@ -87,7 +79,6 @@ export const certificateAuthorityServiceFactory = ({ certificateAuthorityDAL, certificateAuthorityCertDAL, certificateAuthoritySecretDAL, - certificateAuthorityEstConfigDAL, certificateAuthorityCrlDAL, certificateTemplateDAL, certificateDAL, @@ -1540,189 +1531,6 @@ export const certificateAuthorityServiceFactory = ({ }; }; - const createCaEstConfiguration = async ({ - caId, - caChain, - passphrase, - isEnabled, - actorId, - actorAuthMethod, - actor, - actorOrgId - }: TCreateCaEstConfigurationDTO) => { - const ca = await certificateAuthorityDAL.findById(caId); - if (!ca) { - throw new NotFoundError({ message: "CA not found" }); - } - - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - ca.projectId, - actorAuthMethod, - actorOrgId - ); - - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.CertificateAuthorities - ); - - const appCfg = getConfig(); - - const certificateManagerKmsId = await getProjectKmsCertificateKeyId({ - projectId: ca.projectId, - projectDAL, - kmsService - }); - - const kmsEncryptor = await kmsService.encryptWithKmsKey({ - kmsId: certificateManagerKmsId - }); - - const { cipherTextBlob: encryptedCaChain } = await kmsEncryptor({ - plainText: Buffer.from(caChain) - }); - - const hashedPassphrase = await bcrypt.hash(passphrase, appCfg.SALT_ROUNDS); - - const estConfig = await certificateAuthorityEstConfigDAL.create({ - caId, - hashedPassphrase, - encryptedCaChain, - isEnabled - }); - - return estConfig; - }; - - const updateCaEstConfiguration = async ({ - caId, - caChain, - passphrase, - isEnabled, - actorId, - actorAuthMethod, - actor, - actorOrgId - }: TUpdateCaEstConfigurationDTO) => { - const ca = await certificateAuthorityDAL.findById(caId); - if (!ca) { - throw new NotFoundError({ message: "CA not found" }); - } - - const { permission } = await permissionService.getProjectPermission( - actor, - actorId, - ca.projectId, - actorAuthMethod, - actorOrgId - ); - - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.CertificateAuthorities - ); - - const originalCaEstConfig = await certificateAuthorityEstConfigDAL.findOne({ - caId - }); - - if (!originalCaEstConfig) { - throw new NotFoundError({ - message: "CA EST Config not found" - }); - } - - const appCfg = getConfig(); - - const certificateManagerKmsId = await getProjectKmsCertificateKeyId({ - projectId: ca.projectId, - projectDAL, - kmsService - }); - - const updatedData: TCertificateAuthorityEstConfigsUpdate = { - isEnabled - }; - - if (caChain) { - const kmsEncryptor = await kmsService.encryptWithKmsKey({ - kmsId: certificateManagerKmsId - }); - - const { cipherTextBlob: encryptedCaChain } = await kmsEncryptor({ - plainText: Buffer.from(caChain) - }); - - updatedData.encryptedCaChain = encryptedCaChain; - } - - if (passphrase) { - const hashedPassphrase = await bcrypt.hash(passphrase, appCfg.SALT_ROUNDS); - updatedData.hashedPassphrase = hashedPassphrase; - } - - const estConfig = await certificateAuthorityEstConfigDAL.updateById(originalCaEstConfig.id, updatedData); - - return estConfig; - }; - - const getCaEstConfiguration = async (dto: TGetCaEstConfigurationDTO) => { - const ca = await certificateAuthorityDAL.findById(dto.caId); - if (!ca) { - throw new NotFoundError({ message: "CA not found" }); - } - - if (!dto.isInternal) { - const { permission } = await permissionService.getProjectPermission( - dto.actor, - dto.actorId, - ca.projectId, - dto.actorAuthMethod, - dto.actorOrgId - ); - - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionActions.Edit, - ProjectPermissionSub.CertificateAuthorities - ); - } - - const { caId } = dto; - - const caEstConfig = await certificateAuthorityEstConfigDAL.findOne({ - caId - }); - - if (!caEstConfig) { - throw new NotFoundError({ - message: "CA EST Config not found" - }); - } - - const certificateManagerKmsId = await getProjectKmsCertificateKeyId({ - projectId: ca.projectId, - projectDAL, - kmsService - }); - - const kmsDecryptor = await kmsService.decryptWithKmsKey({ - kmsId: certificateManagerKmsId - }); - - const decryptedCaChain = await kmsDecryptor({ - cipherTextBlob: caEstConfig.encryptedCaChain - }); - - return { - caId, - isEnabled: caEstConfig.isEnabled, - caChain: decryptedCaChain.toString(), - hashedPassphrase: caEstConfig.hashedPassphrase - }; - }; - return { createCa, getCaById, @@ -1735,9 +1543,6 @@ export const certificateAuthorityServiceFactory = ({ signIntermediate, importCertToCa, issueCertFromCa, - signCertFromCa, - createCaEstConfiguration, - updateCaEstConfiguration, - getCaEstConfiguration + signCertFromCa }; }; diff --git a/backend/src/services/certificate-authority/certificate-authority-types.ts b/backend/src/services/certificate-authority/certificate-authority-types.ts index 9c2feea37..b065eb90d 100644 --- a/backend/src/services/certificate-authority/certificate-authority-types.ts +++ b/backend/src/services/certificate-authority/certificate-authority-types.ts @@ -172,27 +172,3 @@ export type TRotateCaCrlTriggerDTO = { caId: string; rotationIntervalDays: number; }; - -export type TCreateCaEstConfigurationDTO = { - caId: string; - caChain: string; - passphrase: string; - isEnabled: boolean; -} & Omit; - -export type TUpdateCaEstConfigurationDTO = { - caId: string; - caChain?: string; - passphrase?: string; - isEnabled?: boolean; -} & Omit; - -export type TGetCaEstConfigurationDTO = - | { - isInternal: true; - caId: string; - } - | ({ - isInternal: false; - caId: string; - } & Omit); diff --git a/backend/src/services/certificate-template/certificate-template-est-config-dal.ts b/backend/src/services/certificate-template/certificate-template-est-config-dal.ts new file mode 100644 index 000000000..99d137c5a --- /dev/null +++ b/backend/src/services/certificate-template/certificate-template-est-config-dal.ts @@ -0,0 +1,11 @@ +import { TDbClient } from "@app/db"; +import { TableName } from "@app/db/schemas"; +import { ormify } from "@app/lib/knex"; + +export type TCertificateTemplateEstConfigDALFactory = ReturnType; + +export const certificateTemplateEstConfigDALFactory = (db: TDbClient) => { + const certificateTemplateEstConfigOrm = ormify(db, TableName.CertificateTemplateEstConfig); + + return certificateTemplateEstConfigOrm; +}; diff --git a/backend/src/services/certificate-template/certificate-template-service.ts b/backend/src/services/certificate-template/certificate-template-service.ts index c49791175..f18034058 100644 --- a/backend/src/services/certificate-template/certificate-template-service.ts +++ b/backend/src/services/certificate-template/certificate-template-service.ts @@ -1,20 +1,33 @@ import { ForbiddenError } from "@casl/ability"; +import bcrypt from "bcrypt"; +import { TCertificateTemplateEstConfigsUpdate } from "@app/db/schemas"; import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service"; import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; +import { getConfig } from "@app/lib/config/env"; import { BadRequestError, NotFoundError } from "@app/lib/errors"; import { TCertificateAuthorityDALFactory } from "../certificate-authority/certificate-authority-dal"; +import { TKmsServiceFactory } from "../kms/kms-service"; +import { TProjectDALFactory } from "../project/project-dal"; +import { getProjectKmsCertificateKeyId } from "../project/project-fns"; import { TCertificateTemplateDALFactory } from "./certificate-template-dal"; +import { TCertificateTemplateEstConfigDALFactory } from "./certificate-template-est-config-dal"; import { TCreateCertTemplateDTO, + TCreateEstConfigurationDTO, TDeleteCertTemplateDTO, TGetCertTemplateDTO, - TUpdateCertTemplateDTO + TGetEstConfigurationDTO, + TUpdateCertTemplateDTO, + TUpdateEstConfigurationDTO } from "./certificate-template-types"; type TCertificateTemplateServiceFactoryDep = { certificateTemplateDAL: TCertificateTemplateDALFactory; + certificateTemplateEstConfigDAL: TCertificateTemplateEstConfigDALFactory; + projectDAL: Pick; + kmsService: Pick; certificateAuthorityDAL: Pick; permissionService: Pick; }; @@ -23,8 +36,11 @@ export type TCertificateTemplateServiceFactory = ReturnType { const createCertTemplate = async ({ caId, @@ -187,10 +203,202 @@ export const certificateTemplateServiceFactory = ({ return certTemplate; }; + const createEstConfiguration = async ({ + certificateTemplateId, + caChain, + passphrase, + isEnabled, + actorId, + actorAuthMethod, + actor, + actorOrgId + }: TCreateEstConfigurationDTO) => { + const certTemplate = await certificateTemplateDAL.getById(certificateTemplateId); + if (!certTemplate) { + throw new NotFoundError({ + message: "Certificate template not found." + }); + } + + const { permission } = await permissionService.getProjectPermission( + actor, + actorId, + certTemplate.projectId, + actorAuthMethod, + actorOrgId + ); + + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionActions.Edit, + ProjectPermissionSub.CertificateTemplates + ); + + const appCfg = getConfig(); + + const certificateManagerKmsId = await getProjectKmsCertificateKeyId({ + projectId: certTemplate.projectId, + projectDAL, + kmsService + }); + + const kmsEncryptor = await kmsService.encryptWithKmsKey({ + kmsId: certificateManagerKmsId + }); + + const { cipherTextBlob: encryptedCaChain } = await kmsEncryptor({ + plainText: Buffer.from(caChain) + }); + + const hashedPassphrase = await bcrypt.hash(passphrase, appCfg.SALT_ROUNDS); + const estConfig = await certificateTemplateEstConfigDAL.create({ + certificateTemplateId, + hashedPassphrase, + encryptedCaChain, + isEnabled + }); + + return estConfig; + }; + + const updateEstConfiguration = async ({ + certificateTemplateId, + caChain, + passphrase, + isEnabled, + actorId, + actorAuthMethod, + actor, + actorOrgId + }: TUpdateEstConfigurationDTO) => { + const certTemplate = await certificateTemplateDAL.getById(certificateTemplateId); + if (!certTemplate) { + throw new NotFoundError({ + message: "Certificate template not found." + }); + } + + const { permission } = await permissionService.getProjectPermission( + actor, + actorId, + certTemplate.projectId, + actorAuthMethod, + actorOrgId + ); + + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionActions.Edit, + ProjectPermissionSub.CertificateTemplates + ); + + const originalCaEstConfig = await certificateTemplateEstConfigDAL.findOne({ + certificateTemplateId + }); + + if (!originalCaEstConfig) { + throw new NotFoundError({ + message: "EST configuration not found" + }); + } + + const appCfg = getConfig(); + + const certificateManagerKmsId = await getProjectKmsCertificateKeyId({ + projectId: certTemplate.projectId, + projectDAL, + kmsService + }); + + const updatedData: TCertificateTemplateEstConfigsUpdate = { + isEnabled + }; + + if (caChain) { + const kmsEncryptor = await kmsService.encryptWithKmsKey({ + kmsId: certificateManagerKmsId + }); + + const { cipherTextBlob: encryptedCaChain } = await kmsEncryptor({ + plainText: Buffer.from(caChain) + }); + + updatedData.encryptedCaChain = encryptedCaChain; + } + + if (passphrase) { + const hashedPassphrase = await bcrypt.hash(passphrase, appCfg.SALT_ROUNDS); + updatedData.hashedPassphrase = hashedPassphrase; + } + + const estConfig = await certificateTemplateEstConfigDAL.updateById(originalCaEstConfig.id, updatedData); + + return estConfig; + }; + + const getEstConfiguration = async (dto: TGetEstConfigurationDTO) => { + const { certificateTemplateId } = dto; + + const certTemplate = await certificateTemplateDAL.getById(certificateTemplateId); + if (!certTemplate) { + throw new NotFoundError({ + message: "Certificate template not found." + }); + } + + if (!dto.isInternal) { + const { permission } = await permissionService.getProjectPermission( + dto.actor, + dto.actorId, + certTemplate.projectId, + dto.actorAuthMethod, + dto.actorOrgId + ); + + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionActions.Edit, + ProjectPermissionSub.CertificateTemplates + ); + } + + const estConfig = await certificateTemplateEstConfigDAL.findOne({ + certificateTemplateId + }); + + if (!estConfig) { + throw new NotFoundError({ + message: "EST configuration not found" + }); + } + + const certificateManagerKmsId = await getProjectKmsCertificateKeyId({ + projectId: certTemplate.projectId, + projectDAL, + kmsService + }); + + const kmsDecryptor = await kmsService.decryptWithKmsKey({ + kmsId: certificateManagerKmsId + }); + + const decryptedCaChain = await kmsDecryptor({ + cipherTextBlob: estConfig.encryptedCaChain + }); + + return { + certificateTemplateId, + id: estConfig.id, + isEnabled: estConfig.isEnabled, + caChain: decryptedCaChain.toString(), + hashedPassphrase: estConfig.hashedPassphrase + }; + }; + return { createCertTemplate, getCertTemplate, deleteCertTemplate, - updateCertTemplate + updateCertTemplate, + createEstConfiguration, + updateEstConfiguration, + getEstConfiguration }; }; diff --git a/backend/src/services/certificate-template/certificate-template-types.ts b/backend/src/services/certificate-template/certificate-template-types.ts index c203b386c..74281e7b8 100644 --- a/backend/src/services/certificate-template/certificate-template-types.ts +++ b/backend/src/services/certificate-template/certificate-template-types.ts @@ -26,3 +26,27 @@ export type TGetCertTemplateDTO = { export type TDeleteCertTemplateDTO = { id: string; } & Omit; + +export type TCreateEstConfigurationDTO = { + certificateTemplateId: string; + caChain: string; + passphrase: string; + isEnabled: boolean; +} & Omit; + +export type TUpdateEstConfigurationDTO = { + certificateTemplateId: string; + caChain?: string; + passphrase?: string; + isEnabled?: boolean; +} & Omit; + +export type TGetEstConfigurationDTO = + | { + isInternal: true; + certificateTemplateId: string; + } + | ({ + isInternal: false; + certificateTemplateId: string; + } & Omit); diff --git a/frontend/src/hooks/api/ca/index.tsx b/frontend/src/hooks/api/ca/index.tsx index 6d184f6ce..980624f32 100644 --- a/frontend/src/hooks/api/ca/index.tsx +++ b/frontend/src/hooks/api/ca/index.tsx @@ -1,20 +1,11 @@ export { CaRenewalType, CaStatus, CaType } from "./enums"; export { useCreateCa, - useCreateCaEstConfig, useCreateCertificate, useDeleteCa, useImportCaCertificate, useRenewCa, useSignIntermediate, - useUpdateCa, - useUpdateCaEstConfig + useUpdateCa } from "./mutations"; -export { - useGetCaById, - useGetCaCert, - useGetCaCerts, - useGetCaCrl, - useGetCaCsr, - useGetCaEstConfig -} from "./queries"; +export { useGetCaById, useGetCaCert, useGetCaCerts, useGetCaCrl, useGetCaCsr } from "./queries"; diff --git a/frontend/src/hooks/api/ca/mutations.tsx b/frontend/src/hooks/api/ca/mutations.tsx index fc8ec24d6..48652f3fd 100644 --- a/frontend/src/hooks/api/ca/mutations.tsx +++ b/frontend/src/hooks/api/ca/mutations.tsx @@ -7,7 +7,6 @@ import { caKeys } from "./queries"; import { TCertificateAuthority, TCreateCaDTO, - TCreateCaEstConfigDTO, TCreateCertificateDTO, TCreateCertificateResponse, TDeleteCaDTO, @@ -17,8 +16,7 @@ import { TRenewCaResponse, TSignIntermediateDTO, TSignIntermediateResponse, - TUpdateCaDTO, - TUpdateCaEstConfigDTO + TUpdateCaDTO } from "./types"; export const useCreateCa = () => { @@ -134,29 +132,3 @@ export const useRenewCa = () => { } }); }; - -export const useCreateCaEstConfig = () => { - const queryClient = useQueryClient(); - return useMutation<{}, {}, TCreateCaEstConfigDTO>({ - mutationFn: async (body) => { - const { data } = await apiRequest.post(`/api/v1/pki/ca/${body.caId}/est-config`, body); - return data; - }, - onSuccess: (_, { caId }) => { - queryClient.invalidateQueries(caKeys.getCaEstConfig(caId)); - } - }); -}; - -export const useUpdateCaEstConfig = () => { - const queryClient = useQueryClient(); - return useMutation<{}, {}, TUpdateCaEstConfigDTO>({ - mutationFn: async (body) => { - const { data } = await apiRequest.patch(`/api/v1/pki/ca/${body.caId}/est-config`, body); - return data; - }, - onSuccess: (_, { caId }) => { - queryClient.invalidateQueries(caKeys.getCaEstConfig(caId)); - } - }); -}; diff --git a/frontend/src/hooks/api/ca/queries.tsx b/frontend/src/hooks/api/ca/queries.tsx index d4eb8a8ae..d8f809565 100644 --- a/frontend/src/hooks/api/ca/queries.tsx +++ b/frontend/src/hooks/api/ca/queries.tsx @@ -2,7 +2,7 @@ import { useQuery } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { TCaEstConfig, TCertificateAuthority } from "./types"; +import { TCertificateAuthority } from "./types"; export const caKeys = { getCaById: (caId: string) => [{ caId }, "ca"], @@ -88,19 +88,3 @@ export const useGetCaCrl = (caId: string) => { enabled: Boolean(caId) }); }; - -export const useGetCaEstConfig = (caId: string) => { - return useQuery({ - queryKey: caKeys.getCaEstConfig(caId), - queryFn: async () => { - const { - data: { caEstConfig } - } = await apiRequest.get<{ - caEstConfig: TCaEstConfig; - }>(`/api/v1/pki/ca/${caId}/est-config`); - - return caEstConfig; - }, - enabled: Boolean(caId) - }); -}; diff --git a/frontend/src/hooks/api/ca/types.ts b/frontend/src/hooks/api/ca/types.ts index 320551a04..e09ae16b8 100644 --- a/frontend/src/hooks/api/ca/types.ts +++ b/frontend/src/hooks/api/ca/types.ts @@ -110,23 +110,3 @@ export type TRenewCaResponse = { certificateChain: string; serialNumber: string; }; - -export type TCaEstConfig = { - caId: string; - caChain: string; - isEnabled: false; -}; - -export type TCreateCaEstConfigDTO = { - caId: string; - caChain: string; - passphrase: string; - isEnabled: boolean; -}; - -export type TUpdateCaEstConfigDTO = { - caId: string; - caChain?: string; - passphrase?: string; - isEnabled?: boolean; -}; diff --git a/frontend/src/hooks/api/certificateTemplates/index.tsx b/frontend/src/hooks/api/certificateTemplates/index.tsx index b8145fbcc..61dfb35a2 100644 --- a/frontend/src/hooks/api/certificateTemplates/index.tsx +++ b/frontend/src/hooks/api/certificateTemplates/index.tsx @@ -1,2 +1,8 @@ -export { useCreateCertTemplate, useDeleteCertTemplate, useUpdateCertTemplate } from "./mutations"; -export { useGetCertTemplate } from "./queries"; +export { + useCreateCertTemplate, + useCreateEstConfig, + useDeleteCertTemplate, + useUpdateCertTemplate, + useUpdateEstConfig +} from "./mutations"; +export { useGetCertTemplate, useGetEstConfig } from "./queries"; diff --git a/frontend/src/hooks/api/certificateTemplates/mutations.tsx b/frontend/src/hooks/api/certificateTemplates/mutations.tsx index 269d885a6..101507af0 100644 --- a/frontend/src/hooks/api/certificateTemplates/mutations.tsx +++ b/frontend/src/hooks/api/certificateTemplates/mutations.tsx @@ -7,8 +7,10 @@ import { certTemplateKeys } from "./queries"; import { TCertificateTemplate, TCreateCertificateTemplateDTO, + TCreateEstConfigDTO, TDeleteCertificateTemplateDTO, - TUpdateCertificateTemplateDTO + TUpdateCertificateTemplateDTO, + TUpdateEstConfigDTO } from "./types"; export const useCreateCertTemplate = () => { @@ -57,3 +59,35 @@ export const useDeleteCertTemplate = () => { } }); }; + +export const useCreateEstConfig = () => { + const queryClient = useQueryClient(); + return useMutation<{}, {}, TCreateEstConfigDTO>({ + mutationFn: async (body) => { + const { data } = await apiRequest.post( + `/api/v1/pki/certificate-templates/${body.certificateTemplateId}/est-config`, + body + ); + return data; + }, + onSuccess: (_, { certificateTemplateId }) => { + queryClient.invalidateQueries(certTemplateKeys.getEstConfig(certificateTemplateId)); + } + }); +}; + +export const useUpdateEstConfig = () => { + const queryClient = useQueryClient(); + return useMutation<{}, {}, TUpdateEstConfigDTO>({ + mutationFn: async (body) => { + const { data } = await apiRequest.patch( + `/api/v1/pki/certificate-templates/${body.certificateTemplateId}/est-config`, + body + ); + return data; + }, + onSuccess: (_, { certificateTemplateId }) => { + queryClient.invalidateQueries(certTemplateKeys.getEstConfig(certificateTemplateId)); + } + }); +}; diff --git a/frontend/src/hooks/api/certificateTemplates/queries.tsx b/frontend/src/hooks/api/certificateTemplates/queries.tsx index ca5b088e8..7ee5bbd30 100644 --- a/frontend/src/hooks/api/certificateTemplates/queries.tsx +++ b/frontend/src/hooks/api/certificateTemplates/queries.tsx @@ -2,10 +2,11 @@ import { useQuery } from "@tanstack/react-query"; import { apiRequest } from "@app/config/request"; -import { TCertificateTemplate } from "./types"; +import { TCertificateTemplate, TEstConfig } from "./types"; export const certTemplateKeys = { - getCertTemplateById: (id: string) => [{ id }, "cert-template"] + getCertTemplateById: (id: string) => [{ id }, "cert-template"], + getEstConfig: (id: string) => [{ id }, "cert-template-est-config"] }; export const useGetCertTemplate = (id: string) => { @@ -20,3 +21,17 @@ export const useGetCertTemplate = (id: string) => { enabled: Boolean(id) }); }; + +export const useGetEstConfig = (certificateTemplateId: string) => { + return useQuery({ + queryKey: certTemplateKeys.getEstConfig(certificateTemplateId), + queryFn: async () => { + const { data: estConfig } = await apiRequest.get( + `/api/v1/pki/certificate-templates/${certificateTemplateId}/est-config` + ); + + return estConfig; + }, + enabled: Boolean(certificateTemplateId) + }); +}; diff --git a/frontend/src/hooks/api/certificateTemplates/types.ts b/frontend/src/hooks/api/certificateTemplates/types.ts index 237a86a5e..c7c69c3a2 100644 --- a/frontend/src/hooks/api/certificateTemplates/types.ts +++ b/frontend/src/hooks/api/certificateTemplates/types.ts @@ -35,3 +35,24 @@ export type TDeleteCertificateTemplateDTO = { id: string; projectId: string; }; + +export type TCreateEstConfigDTO = { + certificateTemplateId: string; + caChain: string; + passphrase: string; + isEnabled: boolean; +}; + +export type TUpdateEstConfigDTO = { + certificateTemplateId: string; + caChain?: string; + passphrase?: string; + isEnabled?: boolean; +}; + +export type TEstConfig = { + id: string; + certificateTemplateId: string; + caChain: string; + isEnabled: false; +}; diff --git a/frontend/src/views/Project/CaPage/components/CaEnrollmentModal.tsx b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateTemplateEnrollmentModal.tsx similarity index 90% rename from frontend/src/views/Project/CaPage/components/CaEnrollmentModal.tsx rename to frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateTemplateEnrollmentModal.tsx index df03a6b11..e79fc5451 100644 --- a/frontend/src/views/Project/CaPage/components/CaEnrollmentModal.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateTemplateEnrollmentModal.tsx @@ -15,7 +15,7 @@ import { Switch, TextArea } from "@app/components/v2"; -import { useCreateCaEstConfig, useGetCaEstConfig, useUpdateCaEstConfig } from "@app/hooks/api"; +import { useCreateEstConfig, useGetEstConfig, useUpdateEstConfig } from "@app/hooks/api"; import { UsePopUpState } from "@app/hooks/usePopUp"; enum EnrollmentMethod { @@ -39,13 +39,13 @@ const schema = z.object({ export type FormData = z.infer; -export const CaEnrollmentModal = ({ popUp, handlePopUpToggle }: Props) => { +export const CertificateTemplateEnrollmentModal = ({ popUp, handlePopUpToggle }: Props) => { const popUpData = popUp?.enrollmentOptions?.data as { - caId: string; + id: string; }; - const caId = popUpData?.caId; + const certificateTemplateId = popUpData?.id; - const { data } = useGetCaEstConfig(caId); + const { data } = useGetEstConfig(certificateTemplateId); const { control, @@ -57,8 +57,8 @@ export const CaEnrollmentModal = ({ popUp, handlePopUpToggle }: Props) => { resolver: zodResolver(schema) }); - const { mutateAsync: createCaEstConfig } = useCreateCaEstConfig(); - const { mutateAsync: updateCaEstConfig } = useUpdateCaEstConfig(); + const { mutateAsync: createEstConfig } = useCreateEstConfig(); + const { mutateAsync: updateEstConfig } = useUpdateEstConfig(); useEffect(() => { if (data) { @@ -77,8 +77,8 @@ export const CaEnrollmentModal = ({ popUp, handlePopUpToggle }: Props) => { const onFormSubmit = async ({ caChain, passphrase, isEnabled }: FormData) => { try { if (data) { - await updateCaEstConfig({ - caId, + await updateEstConfig({ + certificateTemplateId, caChain, passphrase, isEnabled @@ -89,8 +89,8 @@ export const CaEnrollmentModal = ({ popUp, handlePopUpToggle }: Props) => { return; } - await createCaEstConfig({ - caId, + await createEstConfig({ + certificateTemplateId, caChain, passphrase, isEnabled diff --git a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateTemplatesSection.tsx b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateTemplatesSection.tsx index 3341e521c..b74ab201a 100644 --- a/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateTemplatesSection.tsx +++ b/frontend/src/views/Project/CertificatesPage/components/CertificatesTab/components/CertificateTemplatesSection.tsx @@ -8,13 +8,15 @@ import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@a import { usePopUp } from "@app/hooks"; import { useDeleteCertTemplate } from "@app/hooks/api"; +import { CertificateTemplateEnrollmentModal } from "./CertificateTemplateEnrollmentModal"; import { CertificateTemplateModal } from "./CertificateTemplateModal"; import { CertificateTemplatesTable } from "./CertificateTemplatesTable"; export const CertificateTemplatesSection = () => { const { popUp, handlePopUpOpen, handlePopUpClose, handlePopUpToggle } = usePopUp([ "certificateTemplate", - "deleteCertificateTemplate" + "deleteCertificateTemplate", + "enrollmentOptions" ] as const); const { currentWorkspace } = useWorkspace(); @@ -69,6 +71,7 @@ export const CertificateTemplatesSection = () => { + , + popUpName: keyof UsePopUpState< + ["certificateTemplate", "deleteCertificateTemplate", "enrollmentOptions"] + >, data?: { id?: string; name?: string; @@ -78,6 +80,16 @@ export const CertificateTemplatesTable = ({ handlePopUpOpen }: Props) => { > Manage Policies + + handlePopUpOpen("enrollmentOptions", { + id: certificateTemplate.id + }) + } + icon={} + > + Manage Enrollment +