]*class[^>]*error[^>]*>(.*?)<\/span>/i,
- /error[^<]*:([^<]*)/i,
- /denied[^<]*:([^<]*)/i,
- /The\s+request\s+contains\s+no\s+certificate\s+template\s+information/i,
- /The\s+template\s+is\s+missing/i
+ new RE2('The disposition message is "([^"]*)"', "i"),
+ new RE2('Denied by Policy Module[^"]*"([^"]*)"', "i"),
+ new RE2("]*class[^>]*error[^>]*>(.*?)<\\/p>", "i"),
+ new RE2("
]*class[^>]*error[^>]*>(.*?)<\\/div>", "i"),
+ new RE2("]*class[^>]*error[^>]*>(.*?)<\\/span>", "i"),
+ new RE2("error[^<]*:([^<]*)", "i"),
+ new RE2("denied[^<]*:([^<]*)", "i"),
+ new RE2("The\\s+request\\s+contains\\s+no\\s+certificate\\s+template\\s+information", "i"),
+ new RE2("The\\s+template\\s+is\\s+missing", "i")
];
// Try each pattern to find the error message
diff --git a/backend/src/services/certificate-authority/azure-ad-cs/azure-ad-cs-certificate-authority-schemas.ts b/backend/src/services/certificate-authority/azure-ad-cs/azure-ad-cs-certificate-authority-schemas.ts
index 6b737e8e2..89e5ea3fc 100644
--- a/backend/src/services/certificate-authority/azure-ad-cs/azure-ad-cs-certificate-authority-schemas.ts
+++ b/backend/src/services/certificate-authority/azure-ad-cs/azure-ad-cs-certificate-authority-schemas.ts
@@ -11,11 +11,16 @@ export const AzureAdCsCertificateAuthorityConfigurationSchema = z.object({
azureAdcsConnectionId: z.string().uuid().trim().describe("Azure ADCS Connection ID")
});
-export const AzureAdCsCertificateAuthorityCredentialsSchema = z.object({
- clientId: z.string(),
- clientSecret: z.string().optional(),
- certificateThumbprint: z.string().optional()
-});
+export const AzureAdCsCertificateAuthorityCredentialsSchema = z
+ .object({
+ clientId: z.string(),
+ clientSecret: z.string().optional(),
+ certificateThumbprint: z.string().optional()
+ })
+ .refine((data) => data.clientSecret || data.certificateThumbprint, {
+ message: "At least one authentication method (clientSecret or certificateThumbprint) must be provided",
+ path: ["clientSecret"]
+ });
export const AzureAdCsCertificateAuthoritySchema = BaseCertificateAuthoritySchema.extend({
type: z.literal(CaType.AZURE_AD_CS),
diff --git a/backend/src/services/certificate-authority/azure-ad-cs/azure-ad-cs-certificate-authority-types.ts b/backend/src/services/certificate-authority/azure-ad-cs/azure-ad-cs-certificate-authority-types.ts
index b955f4c82..1c4b3699d 100644
--- a/backend/src/services/certificate-authority/azure-ad-cs/azure-ad-cs-certificate-authority-types.ts
+++ b/backend/src/services/certificate-authority/azure-ad-cs/azure-ad-cs-certificate-authority-types.ts
@@ -8,8 +8,6 @@ import {
export type TAzureAdCsCertificateAuthority = z.infer;
-export type TAzureAdCsCertificateAuthorityInput = z.infer;
-
export type TCreateAzureAdCsCertificateAuthorityDTO = z.infer;
export type TUpdateAzureAdCsCertificateAuthorityDTO = z.infer;
diff --git a/backend/src/services/certificate-authority/certificate-authority-maps.ts b/backend/src/services/certificate-authority/certificate-authority-maps.ts
index 746a5c2d6..ef844a1ed 100644
--- a/backend/src/services/certificate-authority/certificate-authority-maps.ts
+++ b/backend/src/services/certificate-authority/certificate-authority-maps.ts
@@ -12,11 +12,7 @@ export const CERTIFICATE_AUTHORITIES_CAPABILITIES_MAP: Record;
diff --git a/backend/src/services/certificate-authority/internal/internal-certificate-authority-fns.ts b/backend/src/services/certificate-authority/internal/internal-certificate-authority-fns.ts
index 0621c20f8..39af971b5 100644
--- a/backend/src/services/certificate-authority/internal/internal-certificate-authority-fns.ts
+++ b/backend/src/services/certificate-authority/internal/internal-certificate-authority-fns.ts
@@ -98,7 +98,7 @@ const buildSubjectDN = (commonName: string, properties?: TPkiSubscriberPropertie
const emailAddress = sanitizeComponent(properties?.emailAddress);
if (emailAddress) {
// Enhanced email validation for DN usage
- const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
+ const emailRegex = new RE2(/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/);
if (emailRegex.test(emailAddress) && emailAddress.length > 5 && emailAddress.length < 64) {
subject += `,E=${emailAddress}`;
}
diff --git a/backend/src/services/certificate/certificate-service.ts b/backend/src/services/certificate/certificate-service.ts
index 72e105781..7adc60d52 100644
--- a/backend/src/services/certificate/certificate-service.ts
+++ b/backend/src/services/certificate/certificate-service.ts
@@ -10,7 +10,6 @@ import {
} from "@app/ee/services/permission/project-permission";
import { crypto } from "@app/lib/crypto/cryptography";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
-import { TAppConnectionDALFactory } from "@app/services/app-connection/app-connection-dal";
import { TCertificateBodyDALFactory } from "@app/services/certificate/certificate-body-dal";
import { TCertificateDALFactory } from "@app/services/certificate/certificate-dal";
import { TCertificateAuthorityCertDALFactory } from "@app/services/certificate-authority/certificate-authority-cert-dal";
@@ -52,7 +51,6 @@ type TCertificateServiceFactoryDep = {
pkiCollectionDAL: Pick;
pkiCollectionItemDAL: Pick;
projectDAL: Pick;
- appConnectionDAL: Pick;
kmsService: Pick;
permissionService: Pick;
};
@@ -70,7 +68,6 @@ export const certificateServiceFactory = ({
pkiCollectionDAL,
pkiCollectionItemDAL,
projectDAL,
- appConnectionDAL,
kmsService,
permissionService
}: TCertificateServiceFactoryDep) => {
diff --git a/backend/src/services/pki-subscriber/pki-subscriber-types.ts b/backend/src/services/pki-subscriber/pki-subscriber-types.ts
index 472975d4d..60b6f51b8 100644
--- a/backend/src/services/pki-subscriber/pki-subscriber-types.ts
+++ b/backend/src/services/pki-subscriber/pki-subscriber-types.ts
@@ -80,4 +80,4 @@ export type TPkiSubscriberProperties = {
state?: string;
locality?: string;
emailAddress?: string;
-}
+};
diff --git a/docs/integrations/app-connections/azure-adcs.mdx b/docs/integrations/app-connections/azure-adcs.mdx
index adff38536..7403604dc 100644
--- a/docs/integrations/app-connections/azure-adcs.mdx
+++ b/docs/integrations/app-connections/azure-adcs.mdx
@@ -24,7 +24,7 @@ Connect Infisical to Microsoft Active Directory Certificate Services (ADCS) for

- Fill in the following information:
+ Fill in the following information:
- **Name**: Friendly name for this ADCS connection (e.g., "Production ADCS")
- **ADCS URL**: Your ADCS web enrollment URL (e.g., `https://adcs.yourdomain.com/certsrv`)
- **Username**: Domain administrator username (format: `DOMAIN\username` or `username@domain.com`)
@@ -34,9 +34,7 @@ Connect Infisical to Microsoft Active Directory Certificate Services (ADCS) for

- Your **Azure ADCS Connection** is now available for use in your Infisical
- projects. 
+ Your **Azure ADCS Connection** is now available for use in your Infisical projects. 
diff --git a/frontend/src/hooks/api/appConnections/types/app-options.ts b/frontend/src/hooks/api/appConnections/types/app-options.ts
index 195e925da..67d8feb48 100644
--- a/frontend/src/hooks/api/appConnections/types/app-options.ts
+++ b/frontend/src/hooks/api/appConnections/types/app-options.ts
@@ -205,7 +205,8 @@ export type TAppConnectionOption =
| TSupabaseConnectionOption
| TDigitalOceanConnectionOption
| TNetlifyConnectionOption
- | TOktaConnectionOption;
+ | TOktaConnectionOption
+ | TAzureAdCsConnectionOption;
export type TAppConnectionOptionMap = {
[AppConnection.AWS]: TAwsConnectionOption;
diff --git a/frontend/src/hooks/api/appConnections/types/azure-adcs-connection.ts b/frontend/src/hooks/api/appConnections/types/azure-adcs-connection.ts
index daed7e511..2da9d56b5 100644
--- a/frontend/src/hooks/api/appConnections/types/azure-adcs-connection.ts
+++ b/frontend/src/hooks/api/appConnections/types/azure-adcs-connection.ts
@@ -17,9 +17,5 @@ export type TCreateAzureADCSConnection = z.infer {
});
// Invalidate external CAs list
queryClient.invalidateQueries({
- queryKey: [`external-cas-${projectId}`]
+ queryKey: caKeys.listExternalCasByProjectId(projectId)
});
}
});
@@ -63,7 +63,7 @@ export const useCreateCa = () => {
});
// Invalidate external CAs list
queryClient.invalidateQueries({
- queryKey: [`external-cas-${projectId}`]
+ queryKey: caKeys.listExternalCasByProjectId(projectId)
});
}
});
@@ -89,7 +89,7 @@ export const useDeleteCa = () => {
});
// Invalidate external CAs list
queryClient.invalidateQueries({
- queryKey: [`external-cas-${projectId}`]
+ queryKey: caKeys.listExternalCasByProjectId(projectId)
});
}
});
diff --git a/frontend/src/hooks/api/ca/queries.tsx b/frontend/src/hooks/api/ca/queries.tsx
index b215fdcc1..68e8d2c12 100644
--- a/frontend/src/hooks/api/ca/queries.tsx
+++ b/frontend/src/hooks/api/ca/queries.tsx
@@ -4,13 +4,14 @@ import { apiRequest } from "@app/config/request";
import { TCertificateTemplate } from "../certificateTemplates/types";
import { CaType } from "./enums";
-import { TCertificateAuthority, TUnifiedCertificateAuthority } from "./types";
+import { TAzureAdCsTemplate, TCertificateAuthority, TUnifiedCertificateAuthority } from "./types";
export const caKeys = {
getCaById: (caId: string) => [{ caId }, "ca"],
getCaByNameAndProjectId: (caName: string, projectId: string) => [{ caName, projectId }, "ca"],
listCasByTypeAndProjectId: (type: CaType, projectId: string) => [{ type, projectId }, "cas"],
listCasByProjectId: (projectId: string) => [{ projectId }, "cas"],
+ listExternalCasByProjectId: (projectId: string) => [{ projectId }, "external-cas"],
getCaCerts: (caId: string) => [{ caId }, "ca-cert"],
getCaCrls: (caId: string) => [{ caId }, "ca-crls"],
getCaCert: (caId: string) => [{ caId }, "ca-cert"],
@@ -73,7 +74,7 @@ export const useListCasByProjectId = (projectId: string) => {
export const useListExternalCasByProjectId = (projectId: string) => {
return useQuery({
- queryKey: [`external-cas-${projectId}`],
+ queryKey: caKeys.listExternalCasByProjectId(projectId),
queryFn: async () => {
const [acmeResponse, azureAdCsResponse] = await Promise.allSettled([
apiRequest.get(
@@ -200,7 +201,7 @@ export const useGetAzureAdcsTemplates = ({
queryKey: caKeys.getAzureAdcsTemplates(caId, projectId),
queryFn: async () => {
const { data } = await apiRequest.get<{
- templates: { id: string; name: string; description?: string }[];
+ templates: TAzureAdCsTemplate[];
}>(`/api/v1/pki/ca/azure-ad-cs/${caId}/templates?projectId=${projectId}`);
return data;
},
diff --git a/frontend/src/hooks/api/ca/types.ts b/frontend/src/hooks/api/ca/types.ts
index 6151f15dd..60b78e7cd 100644
--- a/frontend/src/hooks/api/ca/types.ts
+++ b/frontend/src/hooks/api/ca/types.ts
@@ -137,6 +137,12 @@ export type TSignIntermediateResponse = {
serialNumber: string;
};
+export type TAzureAdCsTemplate = {
+ id: string;
+ name: string;
+ description?: string;
+};
+
export type TImportCaCertificateDTO = {
caId: string;
projectSlug: string;
diff --git a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx
index 6a1ebc247..8b0a88bd0 100644
--- a/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx
+++ b/frontend/src/pages/cert-manager/CertificateAuthoritiesPage/components/ExternalCaModal.tsx
@@ -274,6 +274,8 @@ export const ExternalCaModal = ({ popUp, handlePopUpToggle }: Props) => {
configPayload = {
azureAdcsConnectionId: formConfiguration.azureAdcsConnection.id
};
+ } else {
+ throw new Error("Invalid certificate authority configuration");
}
if (ca) {
diff --git a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx
index f2a75df68..98f83bc02 100644
--- a/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx
+++ b/frontend/src/pages/cert-manager/CertificatesPage/components/CertificatesTable.tsx
@@ -175,8 +175,9 @@ export const CertificatesTable = ({ handlePopUpOpen }: Props) => {
{/* Only show revoke button if CA supports revocation */}
{(() => {
const caType = caCapabilityMap[certificate.caId];
+ // If caId not found in map, assume CA supports revocation to avoid hiding revoke option
const supportsRevocation =
- caType &&
+ !caType ||
caSupportsCapability(caType, CaCapability.REVOKE_CERTIFICATES);
if (!supportsRevocation) {
diff --git a/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberCertificatesTable.tsx b/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberCertificatesTable.tsx
index af0e37e03..62e7337bd 100644
--- a/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberCertificatesTable.tsx
+++ b/frontend/src/pages/cert-manager/PkiSubscriberDetailsByIDPage/components/PkiSubscriberCertificatesTable.tsx
@@ -64,7 +64,7 @@ export const PkiSubscriberCertificatesTable = ({ subscriberName, handlePopUpOpen
);
// Fetch CA data to determine capabilities
- const { data: caData } = useListCasByProjectId(currentWorkspace?.id ?? "");
+ const { data: caData } = useListCasByProjectId(currentWorkspace.id);
// Create mapping from caId to CA type for capability checking
const caCapabilityMap = useMemo(() => {
diff --git a/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberModal.tsx b/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberModal.tsx
index 296b37899..546768523 100644
--- a/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberModal.tsx
+++ b/frontend/src/pages/cert-manager/PkiSubscribersPage/components/PkiSubscriberModal.tsx
@@ -151,8 +151,6 @@ export const PkiSubscriberModal = ({ popUp, handlePopUpToggle }: Props) => {
projectId
});
- console.log(pkiSubscriber);
-
// Initialize form with ALL subscriber data including template
useEffect(() => {
if (pkiSubscriber) {