From fbe510067b344b32df03132ae09b27c82ff046d2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 06:59:25 +0000 Subject: [PATCH 1/5] Initial plan From a27603945a6685964f696fb4cc0ae8bb434a5115 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 07:17:03 +0000 Subject: [PATCH 2/5] Fix: KeyVaultJcaProvider registered at highest priority breaks mTLS with standard keystores Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- sdk/spring/CHANGELOG.md | 4 ++ .../CHANGELOG.md | 2 + .../jca/AzureKeyVaultSslBundleRegistrar.java | 2 +- .../AzureKeyVaultSslBundleRegistrarTests.java | 46 +++++++++++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index f54a01d8607d..6499618ef8bf 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -13,6 +13,10 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. - Add ConnectionDetails for ServiceBus. [#44019](https://github.com/Azure/azure-sdk-for-java/pull/44019). - Add ConnectionDetails for EventHubs. [#47926](https://github.com/Azure/azure-sdk-for-java/pull/47926). +#### Bugs Fixed + +- Fixed `KeyVaultJcaProvider` being registered as the highest-priority JCA security provider, which overrides standard JCA services (`KeyManagerFactory.SunX509`, `Signature` algorithms) and breaks mTLS with standard keystores (JKS, PKCS12). The provider is now added at the end of the provider list, allowing JCA's delayed provider selection to route `KeyVaultPrivateKey` signing operations to the KeyVault implementations without interfering with standard SSL/TLS operations. [#48276](https://github.com/Azure/azure-sdk-for-java/issues/48276) + ### Spring Cloud Azure Docker Compose This section includes changes in `spring-cloud-azure-docker-compose` module. diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md index 70cc9113520a..bc3004eb207a 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md +++ b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md @@ -8,6 +8,8 @@ ### Bugs Fixed +- Fixed `KeyVaultJcaProvider` being registered as the highest-priority JCA security provider, which overrides standard JCA services (`KeyManagerFactory.SunX509`, `Signature` algorithms) and breaks mTLS with standard keystores (JKS, PKCS12). The provider is now added at the end of the provider list, allowing JCA's delayed provider selection to route `KeyVaultPrivateKey` signing operations to the KeyVault implementations without interfering with standard SSL/TLS operations. [#48276](https://github.com/Azure/azure-sdk-for-java/issues/48276) + ### Other Changes ## 7.0.0 (2026-02-03) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrar.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrar.java index 2a94664e3db6..10521f66f533 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrar.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrar.java @@ -137,7 +137,7 @@ private KeyStore initilizeKeyVaultKeyStore(String storeName, configureJcaKeyStoreSystemProperties(jcaVaultProperties, keyStoreProperties, resourceLoader); if (providerConfigured.compareAndSet(false, true)) { Security.removeProvider(KeyVaultJcaProvider.PROVIDER_NAME); - Security.insertProviderAt(new KeyVaultJcaProvider(), 1); + Security.addProvider(new KeyVaultJcaProvider()); } KeyStore azureKeyVaultKeyStore; try { diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java index ba2539ab7c9c..218147075d14 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java @@ -3,8 +3,10 @@ package com.azure.spring.cloud.autoconfigure.implementation.keyvault.jca; +import com.azure.security.keyvault.jca.KeyVaultJcaProvider; import com.azure.spring.cloud.autoconfigure.implementation.keyvault.jca.properties.AzureKeyVaultJcaProperties; import com.azure.spring.cloud.autoconfigure.implementation.keyvault.jca.properties.AzureKeyVaultSslBundleProperties; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.parallel.Isolated; @@ -19,6 +21,7 @@ import org.springframework.util.ClassUtils; import java.security.KeyStore; +import java.security.Security; import java.util.Arrays; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -33,6 +36,11 @@ @ExtendWith({OutputCaptureExtension.class}) class AzureKeyVaultSslBundleRegistrarTests { + @AfterEach + void cleanupProvider() { + Security.removeProvider(KeyVaultJcaProvider.PROVIDER_NAME); + } + @Test void noJcaProviderOnClassPath(CapturedOutput capturedOutput) { AzureKeyVaultSslBundleRegistrar registrar = new AzureKeyVaultSslBundleRegistrar(new AzureKeyVaultJcaProperties(), new AzureKeyVaultSslBundleProperties()); @@ -200,4 +208,42 @@ void registerMultipleSslBundles(CapturedOutput capturedOutput) { }); } } + + @Test + void keyVaultProviderNotInsertedAtHighestPriority(CapturedOutput capturedOutput) { + AzureKeyVaultJcaProperties jcaProperties = new AzureKeyVaultJcaProperties(); + AzureKeyVaultSslBundleProperties sslBundleProperties = new AzureKeyVaultSslBundleProperties(); + AzureKeyVaultSslBundleRegistrar registrar = new AzureKeyVaultSslBundleRegistrar(jcaProperties, sslBundleProperties); + registrar.setResourceLoader(new DefaultResourceLoader()); + SslBundleRegistry registry = Mockito.mock(SslBundleRegistry.class); + + try (MockedStatic keyStoreMockedStatic = mockStatic(KeyStore.class)) { + KeyStore keyStore = Mockito.mock(KeyStore.class); + keyStoreMockedStatic.when(() -> KeyStore.getInstance("AzureKeyVault")).thenReturn(keyStore); + + String keyvaultName = "keyvault1"; + AzureKeyVaultJcaProperties.JcaVaultProperties jcaVaultProperties = new AzureKeyVaultJcaProperties.JcaVaultProperties(); + jcaVaultProperties.setEndpoint("https://test.vault.azure.net/"); + jcaProperties.getVaults().put(keyvaultName, jcaVaultProperties); + AzureKeyVaultSslBundleProperties.KeyVaultSslBundleProperties bundleProperties = new AzureKeyVaultSslBundleProperties.KeyVaultSslBundleProperties(); + bundleProperties.getTruststore().setKeyvaultRef(keyvaultName); + sslBundleProperties.getKeyvault().put("testBundle", bundleProperties); + + registrar.registerBundles(registry); + + // Verify the KeyVault JCA provider is NOT inserted at position 1 (highest priority), + // to avoid interfering with standard SSL/TLS operations and breaking mTLS. + java.security.Provider[] providers = Security.getProviders(); + int providerPosition = -1; + for (int i = 0; i < providers.length; i++) { + if (KeyVaultJcaProvider.PROVIDER_NAME.equals(providers[i].getName())) { + providerPosition = i + 1; // 1-indexed position + break; + } + } + assertTrue(providerPosition > 1, "KeyVaultJcaProvider must not be inserted at position 1 " + + "to avoid overriding standard JCA services like KeyManagerFactory.SunX509 and Signature algorithms, " + + "which would break mTLS with standard keystores."); + } + } } From b5d80628baeab429cfdc4b89e2bdb90298f71d99 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 07:45:10 +0000 Subject: [PATCH 3/5] Revert spring-cloud-azure-autoconfigure/CHANGELOG.md - keep aligned with other versions Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md index bc3004eb207a..70cc9113520a 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md +++ b/sdk/spring/spring-cloud-azure-autoconfigure/CHANGELOG.md @@ -8,8 +8,6 @@ ### Bugs Fixed -- Fixed `KeyVaultJcaProvider` being registered as the highest-priority JCA security provider, which overrides standard JCA services (`KeyManagerFactory.SunX509`, `Signature` algorithms) and breaks mTLS with standard keystores (JKS, PKCS12). The provider is now added at the end of the provider list, allowing JCA's delayed provider selection to route `KeyVaultPrivateKey` signing operations to the KeyVault implementations without interfering with standard SSL/TLS operations. [#48276](https://github.com/Azure/azure-sdk-for-java/issues/48276) - ### Other Changes ## 7.0.0 (2026-02-03) From 180979627745443064934dd6e2d225784292d2cf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 07:47:42 +0000 Subject: [PATCH 4/5] Update CHANGELOG issue link to #48183 Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- sdk/spring/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/spring/CHANGELOG.md b/sdk/spring/CHANGELOG.md index 6499618ef8bf..2a1a99ff3300 100644 --- a/sdk/spring/CHANGELOG.md +++ b/sdk/spring/CHANGELOG.md @@ -15,7 +15,7 @@ This section includes changes in `spring-cloud-azure-autoconfigure` module. #### Bugs Fixed -- Fixed `KeyVaultJcaProvider` being registered as the highest-priority JCA security provider, which overrides standard JCA services (`KeyManagerFactory.SunX509`, `Signature` algorithms) and breaks mTLS with standard keystores (JKS, PKCS12). The provider is now added at the end of the provider list, allowing JCA's delayed provider selection to route `KeyVaultPrivateKey` signing operations to the KeyVault implementations without interfering with standard SSL/TLS operations. [#48276](https://github.com/Azure/azure-sdk-for-java/issues/48276) +- Fixed `KeyVaultJcaProvider` being registered as the highest-priority JCA security provider, which overrides standard JCA services (`KeyManagerFactory.SunX509`, `Signature` algorithms) and breaks mTLS with standard keystores (JKS, PKCS12). The provider is now added at the end of the provider list, allowing JCA's delayed provider selection to route `KeyVaultPrivateKey` signing operations to the KeyVault implementations without interfering with standard SSL/TLS operations. [#48183](https://github.com/Azure/azure-sdk-for-java/issues/48183) ### Spring Cloud Azure Docker Compose From f8c0f4ebc32b59b2614e4dcf093115071551abea Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 3 Mar 2026 07:57:06 +0000 Subject: [PATCH 5/5] Apply PR review suggestions: remove unused param and use PROVIDER_NAME constant Co-authored-by: rujche <171773178+rujche@users.noreply.github.com> --- .../keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java index 218147075d14..2d1a99583046 100644 --- a/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java +++ b/sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java @@ -210,7 +210,7 @@ void registerMultipleSslBundles(CapturedOutput capturedOutput) { } @Test - void keyVaultProviderNotInsertedAtHighestPriority(CapturedOutput capturedOutput) { + void keyVaultProviderNotInsertedAtHighestPriority() { AzureKeyVaultJcaProperties jcaProperties = new AzureKeyVaultJcaProperties(); AzureKeyVaultSslBundleProperties sslBundleProperties = new AzureKeyVaultSslBundleProperties(); AzureKeyVaultSslBundleRegistrar registrar = new AzureKeyVaultSslBundleRegistrar(jcaProperties, sslBundleProperties); @@ -219,7 +219,7 @@ void keyVaultProviderNotInsertedAtHighestPriority(CapturedOutput capturedOutput) try (MockedStatic keyStoreMockedStatic = mockStatic(KeyStore.class)) { KeyStore keyStore = Mockito.mock(KeyStore.class); - keyStoreMockedStatic.when(() -> KeyStore.getInstance("AzureKeyVault")).thenReturn(keyStore); + keyStoreMockedStatic.when(() -> KeyStore.getInstance(KeyVaultJcaProvider.PROVIDER_NAME)).thenReturn(keyStore); String keyvaultName = "keyvault1"; AzureKeyVaultJcaProperties.JcaVaultProperties jcaVaultProperties = new AzureKeyVaultJcaProperties.JcaVaultProperties();