Skip to content

Fix Key Vault JCA configuration lifetime and Spring AIA support - #50163

Open
Moary Chen (moarychan) wants to merge 11 commits into
mainfrom
feature/spring-keyvault-jca-disable-aia-download
Open

Fix Key Vault JCA configuration lifetime and Spring AIA support#50163
Moary Chen (moarychan) wants to merge 11 commits into
mainfrom
feature/spring-keyvault-jca-disable-aia-download

Conversation

@moarychan

@moarychan Moary Chen (moarychan) commented Aug 17, 2026

Copy link
Copy Markdown
Member

Summary

  • Support azure.keyvault.jca.disable-aia-download as a per-KeyStore setting. The default remains false.
  • Expose the option through spring.ssl.bundle.keyvault.<bundle-name>.keystore.disable-aia-download and spring.ssl.bundle.keyvault.<bundle-name>.truststore.disable-aia-download.
  • Centralize the supported JCA system property names in KeyVaultJcaPropertyNames.

Bug fix

JCA previously read KeyStore settings from system properties at different times. With multiple Spring SSL bundles, a later bundle could overwrite values before an earlier KeyStore lazily loaded its certificates.

KeyVaultLoadStoreParameter now carries the complete KeyStore, client, cache, filter, path, and AIA configuration. Default construction, system-property initialization, and explicit KeyStore.load(...) each use one configuration snapshot per KeyStore.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
33 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR exposes the Key Vault JCA AIA-download opt-out through Spring SSL bundle configuration and fixes a lifetime/configuration issue by capturing the AIA-disable setting per Key Vault client/keystore instance (instead of relying on a mutable JVM-global system property during lazy chain completion).

Changes:

  • Added Spring SSL bundle properties for disable-aia-download and mapped them to azure.keyvault.jca.disable-aia-download per keystore/truststore initialization.
  • Updated Key Vault JCA internals to pass disableAiaDownload explicitly through certificate loading/chain completion and to retain the setting per KeyVaultClient.
  • Updated/expanded unit tests and documentation to reflect the new per-client behavior and new Spring configuration surface.

Reviewed changes

Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
sdk/spring/spring-cloud-azure-starter-keyvault-jca/pom.xml Bumps the Key Vault JCA dependency to the beta version that contains the per-client AIA configuration changes.
sdk/spring/spring-cloud-azure-autoconfigure/pom.xml Updates optional Key Vault JCA dependency version to align with the new behavior.
sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/properties/AzureKeyVaultSslBundleProperties.java Adds disableAiaDownload boolean to SSL bundle keystore/truststore configuration model.
sdk/spring/spring-cloud-azure-autoconfigure/src/main/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrar.java Maps the new Spring property to azure.keyvault.jca.disable-aia-download prior to JCA keystore initialization.
sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java Verifies the registrar sets the system property appropriately per store initialization.
sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultJcaAutoConfigurationTests.java Verifies property binding for truststore.disable-aia-download (and default false for keystore in another bundle).
sdk/spring/CHANGELOG.md Documents new Spring configuration knobs for disabling AIA downloads.
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java Captures disableAiaDownload at keystore construction time and passes it to certificate/cache layers.
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/KeyVaultClient.java Adds disableAiaDownload as a constructor parameter and uses it when loading certificate chains.
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificates.java Threads disableAiaDownload through client creation/update to retain per-client settings.
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/CertificateUtil.java Makes AIA-disable an explicit input to secret-bundle certificate parsing/chain completion.
sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/implementation/utils/AiaCertificateChainUtil.java Updates AIA completion API to be explicitly gated by a passed disableAiaDownload flag.
sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/AiaCertificateChainTest.java Updates tests to call new APIs and adds coverage for per-client setting retention.
sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/CertificateUtilTest.java Updates tests to use the new loadCertificatesFromSecretBundleValue(..., disableAiaDownload) signature.
sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/CertificateOrderTest.java Updates tests to use the new certificate-loading signature.
sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/KeyVaultClientTest.java Updates static mocking for the new CertificateUtil overload signature.
sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/certificates/KeyVaultCertificatesTest.java Updates updateKeyVaultClient call sites for the new parameter.
sdk/keyvault/azure-security-keyvault-jca/README.md Documents the per-keystore capture semantics for azure.keyvault.jca.disable-aia-download.
sdk/keyvault/azure-security-keyvault-jca/CHANGELOG.md Updates release notes to clarify per-client capture/retention of the AIA-disable setting.

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread sdk/spring/CHANGELOG.md Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Suppressed comments (4)

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultKeyStore.java:127

  • The JavaDoc lists system property keys using camelCase (tenantId/clientId/clientSecret/managedIdentity), but the implementation reads hyphenated keys (tenant-id/client-id/client-secret/managed-identity). This mismatch can mislead users configuring the provider.
     * The constructor uses System.getProperty for
     * <code>azure.keyvault.uri</code>,
     * <code>azure.keyvault.tenantId</code>,
     * <code>azure.keyvault.clientId</code>,
     * <code>azure.keyvault.clientSecret</code>,
     * <code>azure.keyvault.managedIdentity</code>, and
     * <code>azure.keyvault.jca.disable-aia-download</code> to initialize the

sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/AiaCertificateChainTest.java:492

  • This test modifies the JVM-global azure.keyvault.jca.disable-aia-download system property but never restores it. Cleaning up the prior value avoids leaking global state into other tests.
        // Simulate another SSL bundle replacing the JVM-global value before this client lazily loads its chain.
        System.setProperty(AiaCertificateChainUtil.DISABLE_AIA_DOWNLOAD_PROPERTY, "true");

        try (MockedStatic<HttpUtil> httpMock = Mockito.mockStatic(HttpUtil.class)) {
            httpMock
                .when(() -> HttpUtil.get(secretId + HttpUtil.API_VERSION_POSTFIX,
                    Collections.singletonMap("Authorization", "Bearer test-token")))
                .thenReturn(JsonConverterUtil.toJson(secretBundle));
            mockAiaResponse(httpMock, AIA_INTERMEDIATE_URL, intermediateCert.getEncoded());
            mockAiaResponse(httpMock, AIA_ROOT_URL, rootCert.getEncoded());

            Certificate[] result = keyVaultClient.getCertificateChainForVersion(certificateVersion);

            assertArrayEquals(new Certificate[] { leafCert, intermediateCert, rootCert }, result,
                "The client must keep the AIA setting captured when it was constructed");
            httpMock.verify(() -> HttpUtil.getBytesWithMetadata(AIA_INTERMEDIATE_URL), Mockito.times(1));
            httpMock.verify(() -> HttpUtil.getBytesWithMetadata(AIA_ROOT_URL), Mockito.times(1));
        }

sdk/spring/spring-cloud-azure-autoconfigure/src/test/java/com/azure/spring/cloud/autoconfigure/implementation/keyvault/jca/AzureKeyVaultSslBundleRegistrarTests.java:300

  • This test leaves the global system property azure.keyvault.jca.disable-aia-download set after the registrar runs (it ends as "false" for the truststore). Persisting global state can make later tests order-dependent/flaky.
        try (MockedStatic<KeyStore> keyStoreMockedStatic = mockStatic(KeyStore.class)) {
            KeyStore keyStore = Mockito.mock(KeyStore.class);
            List<String> configuredValues = new ArrayList<>();
            keyStoreMockedStatic.when(() -> KeyStore.getInstance(KeyVaultJcaProvider.PROVIDER_NAME))
                .thenAnswer(invocation -> {
                    configuredValues.add(System.getProperty("azure.keyvault.jca.disable-aia-download"));
                    return keyStore;
                });

            AzureKeyVaultJcaProperties.JcaVaultProperties vaultProperties
                = new AzureKeyVaultJcaProperties.JcaVaultProperties();
            vaultProperties.setEndpoint("https://test.vault.azure.net/");
            jcaProperties.getVaults().put("keyvault1", vaultProperties);

            AzureKeyVaultSslBundleProperties.KeyVaultSslBundleProperties bundleProperties
                = new AzureKeyVaultSslBundleProperties.KeyVaultSslBundleProperties();
            bundleProperties.getKeystore().setKeyvaultRef("keyvault1");
            bundleProperties.getKeystore().setDisableAiaDownload(true);
            bundleProperties.getTruststore().setKeyvaultRef("keyvault1");
            sslBundleProperties.getKeyvault().put("testBundle", bundleProperties);

            registrar.registerBundles(Mockito.mock(SslBundleRegistry.class));

            assertThat(configuredValues).containsExactly("true", "false");
        }

sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/implementation/utils/AiaCertificateChainTest.java:461

  • This test modifies the JVM-global azure.keyvault.jca.disable-aia-download system property but never restores it. Even though the test is simulating another bundle overwriting the value, leaving it set can leak into other tests and cause order-dependent failures.

This issue also appears on line 475 of the same file.

        // Simulate another SSL bundle replacing the JVM-global value before this client lazily loads its chain.
        System.setProperty(AiaCertificateChainUtil.DISABLE_AIA_DOWNLOAD_PROPERTY, "false");

        try (MockedStatic<HttpUtil> httpMock = Mockito.mockStatic(HttpUtil.class)) {
            httpMock
                .when(() -> HttpUtil.get(secretId + HttpUtil.API_VERSION_POSTFIX,
                    Collections.singletonMap("Authorization", "Bearer test-token")))
                .thenReturn(JsonConverterUtil.toJson(secretBundle));
            mockAiaResponse(httpMock, AIA_INTERMEDIATE_URL, intermediateCert.getEncoded());
            mockAiaResponse(httpMock, AIA_ROOT_URL, rootCert.getEncoded());

            Certificate[] result = keyVaultClient.getCertificateChainForVersion(certificateVersion);

            assertArrayEquals(new Certificate[] { leafCert }, result,
                "The client must keep the AIA setting captured when it was constructed");
            httpMock.verify(() -> HttpUtil.getBytesWithMetadata(AIA_INTERMEDIATE_URL), Mockito.never());
            httpMock.verify(() -> HttpUtil.getBytesWithMetadata(AIA_ROOT_URL), Mockito.never());
        }

@moarychan

Copy link
Copy Markdown
Member Author

Addressed the four suppressed Copilot comments from review 4949901732 in a800640:

  1. Updated KeyVaultKeyStore JavaDoc to use the actual hyphenated system-property names.
  2. and 4. Verified AiaCertificateChainTest already clears azure.keyvault.jca.disable-aia-download and the AIA cache in @AfterEach (and starts clean in beforeeach), so both global-property override tests are isolated.
  3. Updated AzureKeyVaultSslBundleRegistrarTests cleanup to clear azure.keyvault.jca.disable-aia-download after every test.

Validation:

  • KeyVaultKeyStoreUnitTest + AiaCertificateChainTest: 61 tests passed.
  • AzureKeyVaultSslBundleRegistrarTests: 10 tests passed.
  • Checkstyle: 0 violations; SpotBugs: 0 bugs.

@vcolin7 vcolin7 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functionally, the changes look fine to me. I added a few comments on sticking to the established way of declaring these system properties.

I think we should also get somebody from your team to review this PR because I'm not all that familiar with how things should be done in Spring, Moary Chen (@moarychan).

@moarychan
Moary Chen (moarychan) marked this pull request as draft August 18, 2026 07:41
@moarychan Moary Chen (moarychan) changed the title Support disabling Key Vault JCA AIA downloads in Spring Fix Key Vault JCA configuration lifetime and Spring AIA support Aug 18, 2026
@moarychan
Moary Chen (moarychan) marked this pull request as ready for review August 18, 2026 09:38
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
33 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

azure-spring All azure-spring related issues KeyVault

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

4 participants