From c487614c388f82825532c37876c4d682496a3220 Mon Sep 17 00:00:00 2001 From: carlosmonastyrski Date: Wed, 11 Jun 2025 13:28:34 -0300 Subject: [PATCH] feat(secret-rotation): fix Azure Client Secrets to check if the client secret has been manually deleted to avoid blocking the process --- .../azure-client-secret-rotation-fns.ts | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/backend/src/ee/services/secret-rotation-v2/azure-client-secret/azure-client-secret-rotation-fns.ts b/backend/src/ee/services/secret-rotation-v2/azure-client-secret/azure-client-secret-rotation-fns.ts index 037df50ac..e2969ac1d 100644 --- a/backend/src/ee/services/secret-rotation-v2/azure-client-secret/azure-client-secret-rotation-fns.ts +++ b/backend/src/ee/services/secret-rotation-v2/azure-client-secret/azure-client-secret-rotation-fns.ts @@ -101,10 +101,56 @@ export const azureClientSecretRotationFactory: TRotationFactory< } }; + /** + * Checks if a credential with the given keyId exists. + */ + const credentialExists = async (keyId: string): Promise => { + const accessToken = await getAzureConnectionAccessToken(connection.id, appConnectionDAL, kmsService); + const endpoint = `${GRAPH_API_BASE}/applications/${objectId}/passwordCredentials`; + + try { + const { data } = await request.get<{ value: Array<{ keyId: string }> }>(endpoint, { + headers: { + Authorization: `Bearer ${accessToken}`, + "Content-Type": "application/json" + } + }); + + return data.value?.some((credential) => credential.keyId === keyId) || false; + } catch (error: unknown) { + if (error instanceof AxiosError) { + let message; + if ( + error.response?.data && + typeof error.response.data === "object" && + "error" in error.response.data && + typeof (error.response.data as AzureErrorResponse).error.message === "string" + ) { + message = (error.response.data as AzureErrorResponse).error.message; + } + throw new BadRequestError({ + message: `Failed to check credential existence for app ${objectId}: ${ + message || error.message || "Unknown error" + }` + }); + } + throw new BadRequestError({ + message: "Unable to validate connection: verify credentials" + }); + } + }; + /** * Revokes a client secret from the Azure app using its keyId. + * First checks if the credential exists before attempting revocation. */ const revokeCredential = async (keyId: string) => { + // Check if credential exists before attempting revocation + const exists = await credentialExists(keyId); + if (!exists) { + return; // Credential doesn't exist, nothing to revoke + } + const accessToken = await getAzureConnectionAccessToken(connection.id, appConnectionDAL, kmsService); const endpoint = `${GRAPH_API_BASE}/applications/${objectId}/removePassword`;