Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions sdk/spring/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. [#48183](https://github.com/Azure/azure-sdk-for-java/issues/48183)
Comment thread
rujche marked this conversation as resolved.

### Spring Cloud Azure Docker Compose

This section includes changes in `spring-cloud-azure-docker-compose` module.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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());
Expand Down Expand Up @@ -200,4 +208,42 @@ void registerMultipleSslBundles(CapturedOutput capturedOutput) {
});
}
}

@Test
void keyVaultProviderNotInsertedAtHighestPriority() {
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<KeyStore> keyStoreMockedStatic = mockStatic(KeyStore.class)) {
KeyStore keyStore = Mockito.mock(KeyStore.class);
keyStoreMockedStatic.when(() -> KeyStore.getInstance(KeyVaultJcaProvider.PROVIDER_NAME)).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.");
}
}
}
Loading