From 542f8237711c9c32777008e2b69814c33f65d23f Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Fri, 7 Nov 2025 05:45:51 +0400 Subject: [PATCH] addressed requested changes --- backend/src/lib/api-docs/constants.ts | 2 +- .../azure-client-secrets-connection-fns.ts | 17 +++++++++-------- .../azure-client-secrets-connection-schemas.ts | 8 ++++---- .../app-connections/azure-client-secrets.mdx | 4 ++-- .../types/azure-client-secrets-connection.ts | 2 +- .../AzureClientSecretsConnectionForm.tsx | 12 ++++++++---- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index b0829bd3b..3b81ebfcc 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -2309,7 +2309,7 @@ export const AppConnections = { tenantId: "The Tenant ID to use to connect with Azure Client Secrets.", clientId: "The Client ID to use to connect with Azure Client Secrets.", clientSecret: "The Client Secret to use to connect with Azure Client Secrets.", - certificate: "The certificate to use to connect with Azure Client Secrets.", + certificateBody: "The certificate body in PEM format to use to connect with Azure Client Secrets.", privateKey: "The private key to use to connect with Azure Client Secrets. This is never transmitted to Azure and is only used to sign the Azure client assertion with." }, diff --git a/backend/src/services/app-connection/azure-client-secrets/azure-client-secrets-connection-fns.ts b/backend/src/services/app-connection/azure-client-secrets/azure-client-secrets-connection-fns.ts index d1599cd3e..7916ac92d 100644 --- a/backend/src/services/app-connection/azure-client-secrets/azure-client-secrets-connection-fns.ts +++ b/backend/src/services/app-connection/azure-client-secrets/azure-client-secrets-connection-fns.ts @@ -1,6 +1,7 @@ /* eslint-disable no-case-declarations */ import { AxiosError, AxiosResponse } from "axios"; import type { KeyObject } from "crypto"; +import RE2 from "re2"; import { v4 as uuidv4 } from "uuid"; import { getConfig } from "@app/lib/config/env"; @@ -37,9 +38,9 @@ const generateClientAssertion = ( const certBuffer = Buffer.from( certificate - .replace(/-----BEGIN CERTIFICATE-----/, "") - .replace(/-----END CERTIFICATE-----/, "") - .replace(/\s/g, ""), + .replace(new RE2("-----BEGIN CERTIFICATE-----"), "") + .replace(new RE2("-----END CERTIFICATE-----"), "") + .replace(new RE2("\\s", "g"), ""), "base64" ); @@ -225,12 +226,12 @@ export const getAzureConnectionAccessToken = async ( kmsService, encryptedCredentials: appConnection.encryptedCredentials })) as TAzureClientSecretsConnectionCertificateCredentials; - const { accessToken, expiresAt, clientId, tenantId, certificate, privateKey } = accessTokenCredentials; + const { accessToken, expiresAt, clientId, tenantId, certificateBody, privateKey } = accessTokenCredentials; if (accessToken && expiresAt && expiresAt > currentTime + 300000) { return accessToken; } - const clientAssertion = generateClientAssertion(clientId, tenantId, privateKey, certificate); + const clientAssertion = generateClientAssertion(clientId, tenantId, privateKey, certificateBody); const { data: clientData } = await request.post( IntegrationUrls.AZURE_TOKEN_URL.replace("common", tenantId || "common"), new URLSearchParams({ @@ -379,9 +380,9 @@ export const validateAzureClientSecretsConnectionCredentials = async (config: TA } } case AzureClientSecretsConnectionMethod.Certificate: { - const { tenantId, certificate, privateKey, clientId } = inputCredentials; + const { tenantId, certificateBody, privateKey, clientId } = inputCredentials; try { - const clientAssertion = generateClientAssertion(clientId, tenantId, privateKey, certificate); + const clientAssertion = generateClientAssertion(clientId, tenantId, privateKey, certificateBody); const tokenEndpoint = `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`; @@ -402,7 +403,7 @@ export const validateAzureClientSecretsConnectionCredentials = async (config: TA return { tenantId, clientId, - certificate, + certificateBody, privateKey, accessToken: response.data.access_token, expiresAt: Date.now() + response.data.expires_in * 1000 diff --git a/backend/src/services/app-connection/azure-client-secrets/azure-client-secrets-connection-schemas.ts b/backend/src/services/app-connection/azure-client-secrets/azure-client-secrets-connection-schemas.ts index 3f4130e28..dd387894e 100644 --- a/backend/src/services/app-connection/azure-client-secrets/azure-client-secrets-connection-schemas.ts +++ b/backend/src/services/app-connection/azure-client-secrets/azure-client-secrets-connection-schemas.ts @@ -61,11 +61,11 @@ export const AzureClientSecretsConnectionCertificateInputCredentialsSchema = z.o .trim() .min(1, "Client ID required") .describe(AppConnections.CREDENTIALS.AZURE_CLIENT_SECRETS.clientId), - certificate: z + certificateBody: z .string() .trim() - .min(1, "Certificate required") - .describe(AppConnections.CREDENTIALS.AZURE_CLIENT_SECRETS.certificate), + .min(1, "Certificate body required") + .describe(AppConnections.CREDENTIALS.AZURE_CLIENT_SECRETS.certificateBody), privateKey: z .string() .trim() @@ -84,7 +84,7 @@ export const AzureClientSecretsConnectionClientSecretOutputCredentialsSchema = z export const AzureClientSecretsConnectionCertificateOutputCredentialsSchema = z.object({ clientId: z.string(), tenantId: z.string(), - certificate: z.string(), + certificateBody: z.string(), privateKey: z.string(), accessToken: z.string(), expiresAt: z.number() diff --git a/docs/integrations/app-connections/azure-client-secrets.mdx b/docs/integrations/app-connections/azure-client-secrets.mdx index 6c3b48ef6..4b55a7354 100644 --- a/docs/integrations/app-connections/azure-client-secrets.mdx +++ b/docs/integrations/app-connections/azure-client-secrets.mdx @@ -122,7 +122,7 @@ Infisical currently only supports two methods for connecting to Azure, which are ![Upload certificate](/images/app-connections/azure/client-secrets/upload-certificate.png) - Keep in mind that you'll need the both the certificate & private key in order to configure the Azure Client Secrets connection within Infisical. + Keep in mind that both the certificate and its private key are required to configure the Azure Client Secrets connection in Infisical. @@ -168,7 +168,7 @@ Infisical currently only supports two methods for connecting to Azure, which are - Fill in the **Tenant ID**, **Client ID**, **Certificate**, and **Private Key** fields with the Directory (Tenant) ID, Application (Client) ID, Certificate and Private Key you obtained in the [previous step](#certificate-authentication). + Fill in the **Tenant ID**, **Client ID**, **Certificate (PEM format)**, and **Private Key** fields with the Directory (Tenant) ID, Application (Client) ID, Certificate and Private Key you obtained in the [previous step](#certificate-authentication). The private key is never transmitted to Azure, and it is only used to sign the client assertion used to authenticate with Azure. diff --git a/frontend/src/hooks/api/appConnections/types/azure-client-secrets-connection.ts b/frontend/src/hooks/api/appConnections/types/azure-client-secrets-connection.ts index 4dcea9731..8a648592b 100644 --- a/frontend/src/hooks/api/appConnections/types/azure-client-secrets-connection.ts +++ b/frontend/src/hooks/api/appConnections/types/azure-client-secrets-connection.ts @@ -30,7 +30,7 @@ export type TAzureClientSecretsConnection = TRootAppConnection & { credentials: { clientId: string; tenantId: string; - certificate: string; + certificateBody: string; privateKey: string; }; } diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AzureClientSecretsConnectionForm.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AzureClientSecretsConnectionForm.tsx index b407ecbcd..c91225be9 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AzureClientSecretsConnectionForm.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AzureClientSecretsConnectionForm.tsx @@ -68,7 +68,7 @@ const certificateSchema = baseSchema.extend({ method: z.literal(AzureClientSecretsConnectionMethod.Certificate), credentials: z.object({ clientId: z.string().trim().min(1, "Client ID is required"), - certificate: z.string().trim().min(1, "Certificate is required"), + certificateBody: z.string().trim().min(1, "Certificate is required"), privateKey: z.string().trim().min(1, "Private Key is required"), tenantId: z.string().trim().min(1, "Tenant ID is required") }) @@ -129,7 +129,7 @@ const getDefaultValues = (appConnection?: TAzureClientSecretsConnection): Partia credentials: { clientId: credentials.clientId, tenantId: credentials.tenantId, - certificate: "", + certificateBody: "", privateKey: "" } }; @@ -249,7 +249,11 @@ export const AzureClientSecretsConnectionForm = ({ appConnection, onSubmit, proj /> ( (