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
2 changes: 1 addition & 1 deletion eng/versioning/version_client.txt
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ com.azure:azure-security-attestation;1.2.0;1.3.0-beta.1
com.azure:azure-security-confidentialledger;1.0.38;2.0.2-beta.2
com.azure:azure-security-keyvault-administration;4.8.3;4.9.0-beta.2
com.azure:azure-security-keyvault-certificates;4.9.3;4.10.0-beta.2
com.azure:azure-security-keyvault-jca;2.12.0;2.13.0-beta.1
com.azure:azure-security-keyvault-jca;2.13.0;2.14.0-beta.1
com.azure:azure-security-test-keyvault-jca;1.0.0;1.0.0
com.azure:azure-security-keyvault-keys;4.11.3;4.12.0-beta.3
com.azure:azure-security-keyvault-secrets;4.11.3;4.12.0-beta.1
Expand Down
15 changes: 14 additions & 1 deletion sdk/keyvault/azure-security-keyvault-jca/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
# Release History

## 2.13.0-beta.1 (Unreleased)
## 2.14.0-beta.1 (Unreleased)

### Features Added

### Breaking Changes

### Bugs Fixed

### Other Changes

## 2.13.0 (2026-10-13)

### Features Added
- Added ISO-8601 duration support (e.g., `PT30S`) for `azure.keyvault.jca.certificates-refresh-interval`, while retaining support for millisecond values. ([#50785](https://github.com/Azure/azure-sdk-for-java/pull/50785))
- Added lazy loading for Key Vault certificate details in the JCA keystore. Certificate details are now loaded by alias when requested, avoiding unnecessary reads for unconfigured certificates. ([#49774](https://github.com/Azure/azure-sdk-for-java/pull/49774))
- Added support for `azure.keyvault.jca.certificate-alias-filter-pattern` to filter Key Vault certificate aliases with inclusion/exclusion regex patterns. Inclusion patterns are configured directly and exclusion patterns are prefixed with `!`. Configure more than one filter by appending a suffix to the property name, such as `azure.keyvault.jca.certificate-alias-filter-pattern.1`. A pattern can contain any character as long as the regex is correct. If no filter property is configured, alias filtering is disabled and all discovered Key Vault aliases remain eligible for lazy loading. ([#39487](https://github.com/Azure/azure-sdk-for-java/issues/39487))

### Breaking Changes
- Removed support for `azure.keyvault.jca.certificates-refresh-interval-in-ms`. ([#50785](https://github.com/Azure/azure-sdk-for-java/pull/50785))

### Bugs Fixed
- Preserved configured TLS endpoint identification and connection-specific validation when delegating certificate checks, including checks of certificates trusted through the Key Vault keystore. ([#50667](https://github.com/Azure/azure-sdk-for-java/pull/50667))
Expand All @@ -15,6 +27,7 @@
- Fixed an issue where `KeyStore.load(KeyVaultLoadStoreParameter)` could combine explicit client settings with certificate cache and path settings captured earlier from system properties. The parameter now carries the complete key store configuration. ([#50163](https://github.com/Azure/azure-sdk-for-java/pull/50163))

### Other Changes
- Changed the certificate refresh interval in `KeyVaultLoadStoreParameter` from `long` milliseconds to `Duration`. ([#50785](https://github.com/Azure/azure-sdk-for-java/pull/50785))
- Added system property `azure.keyvault.jca.disable-aia-download` to disable automatic AIA chain completion. AIA chain completion downloads certificates from URLs embedded in certificate extensions, so this allows locked-down environments to prevent those outbound HTTP(S) requests, mitigating potential SSRF-like attack vectors when loading untrusted certificates. The value is captured when each Key Vault client is initialized and retained for lazy certificate-chain loading, so multiple keystores can use different settings without overwriting one another. Set to `true` to disable (defaults to `false`).
- Added `KeyVaultJcaPropertyNames` as the central source for the system property names supported by the Azure Key Vault JCA provider. ([#50163](https://github.com/Azure/azure-sdk-for-java/pull/50163))
- Replaced Apache HttpClient 5 with the JDK `HttpURLConnection`, removing the Apache HttpClient and SLF4J runtime dependencies while preserving strict HTTPS hostname verification, non-fatal AIA download failures, fail-closed TLS trust initialization, and automatic gzip and deflate response decompression. VM managed identity requests to IMDS use `Proxy.NO_PROXY` to bypass HTTP proxy routing. Other requests, including App Service and Container Apps managed identity requests, retain JDK proxy selection.
Expand Down
11 changes: 7 additions & 4 deletions sdk/keyvault/azure-security-keyvault-jca/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ add the direct dependency to your project as follows.
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-jca</artifactId>
<version>2.12.0</version>
<version>2.13.0</version>
</dependency>
```
[//]: # ({x-version-update-end})
Expand Down Expand Up @@ -139,8 +139,7 @@ The JCA library supports configuring the following options:
* `azure.cert-path.well-known`: The path where the well-known certificate is stored.
* `azure.cert-path.custom`: The path where the custom certificate is stored.
* `azure.keyvault.jca.refresh-certificates-when-have-un-trust-certificate`: Indicates whether to refresh certificates when have untrusted certificate.
* `azure.keyvault.jca.certificates-refresh-interval`: The refresh interval time.
* `azure.keyvault.jca.certificates-refresh-interval-in-ms`: The refresh interval time.
* `azure.keyvault.jca.certificates-refresh-interval`: The certificate refresh interval as an ISO-8601 duration, for example `-Dazure.keyvault.jca.certificates-refresh-interval=PT30S` for 30 seconds. Millisecond values such as `-Dazure.keyvault.jca.certificates-refresh-interval=30000` remain supported for backward compatibility. Defaults to zero; zero or negative values disable periodic refresh.
* `azure.keyvault.jca.certificate-alias-filter-pattern`: A regex that filters which Key Vault certificate aliases are eligible for lazy loading. Append a suffix to the property name to configure more than one filter, for example `azure.keyvault.jca.certificate-alias-filter-pattern.1` or `azure.keyvault.jca.certificate-alias-filter-pattern.prod`. If no such property is configured, all discovered Key Vault aliases are eligible for lazy loading. See "Filtering Key Vault certificate aliases" below.
* `azure.keyvault.disable-challenge-resource-verification`: Indicates whether to disable verification that the authentication challenge resource matches the Key Vault or Managed HSM domain.
* `azure.keyvault.jca.disable-aia-download`: Set to `true` to disable automatic AIA (Authority Information Access) certificate chain completion. Chain completion is only attempted when the chain returned by Azure Key Vault is incomplete, meaning it holds a single certificate or is missing an intermediate CA. When disabled, the provider will return certificate chains as provided by Azure Key Vault without downloading missing intermediate CA certificates. Use this in locked-down environments or when processing untrusted certificates to prevent outbound HTTP(S) requests to URLs embedded in certificate extensions. Defaults to `false` for backward compatibility. The value is captured when a Key Vault keystore and its client are initialized.
Expand All @@ -154,6 +153,10 @@ or as a JVM argument:
-Dazure.keyvault.uri=<your-azure-keyvault-uri>
```

The system property `azure.keyvault.jca.certificates-refresh-interval-in-ms` has been removed and is ignored. If it is
configured, the provider logs a warning. Use `azure.keyvault.jca.certificates-refresh-interval` instead, with an ISO-8601
duration such as `PT30S` or the existing millisecond value.

#### Programmatic configuration

Use `KeyVaultLoadStoreParameter` when each key store needs an explicit configuration instead of global system
Expand All @@ -165,7 +168,7 @@ KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
"<your-tenant-id>",
"<your-client-id>",
"<your-client-secret>")
.setCertificatesRefreshIntervalInMs(60_000)
.setCertificatesRefreshInterval(Duration.ofSeconds(60))
.setCertificateAliasFilterPatterns(Collections.singleton("^prod-.*"));
parameter.disableAiaDownload();

Expand Down
2 changes: 1 addition & 1 deletion sdk/keyvault/azure-security-keyvault-jca/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

<groupId>com.azure</groupId>
<artifactId>azure-security-keyvault-jca</artifactId>
<version>2.13.0-beta.1</version> <!-- {x-version-update;com.azure:azure-security-keyvault-jca;current} -->
<version>2.14.0-beta.1</version> <!-- {x-version-update;com.azure:azure-security-keyvault-jca;current} -->
<name>JCA Provider for Azure Key Vault</name>
<description>The Java Crypto Architecture (JCA) Provider for Azure Key Vault</description>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,12 @@ private KeyVaultJcaPropertyNames() {
public static final String CERT_PATH_CUSTOM = "azure.cert-path.custom";

/**
* The certificate refresh interval property name.
* The certificate refresh interval property name. Accepts an ISO-8601 duration, such as {@code PT30S}, or a
* millisecond value, such as {@code 30000}.
*/
public static final String KEYVAULT_JCA_CERTIFICATES_REFRESH_INTERVAL
= "azure.keyvault.jca.certificates-refresh-interval";

/**
* The certificate refresh interval in milliseconds property name.
*/
public static final String KEYVAULT_JCA_CERTIFICATES_REFRESH_INTERVAL_IN_MS
= "azure.keyvault.jca.certificates-refresh-interval-in-ms";

/**
* The property name used to refresh certificates when an untrusted certificate is encountered.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ public final class KeyVaultKeyStore extends KeyStoreSpi {
*/
private static final Logger LOGGER = Logger.getLogger(KeyVaultKeyStore.class.getName());

private static final String REMOVED_CERTIFICATES_REFRESH_INTERVAL_IN_MS
= "azure.keyvault.jca.certificates-refresh-interval-in-ms";

/**
* Stores the Jre key store certificates.
*/
Expand Down Expand Up @@ -123,6 +126,17 @@ public KeyVaultKeyStore() {
updateKeyStoreConfiguration(parameter);
}

static void warnIfRemovedCertificatesRefreshIntervalIsConfigured() {
if (System.getProperty(REMOVED_CERTIFICATES_REFRESH_INTERVAL_IN_MS) != null) {
LOGGER.log(WARNING,
"System property {0} has been removed and is ignored. Use {1} instead with an ISO-8601 duration"
+ " (for example, PT30S). Millisecond values (for example, 30000) are also supported.",
new Object[] {
REMOVED_CERTIFICATES_REFRESH_INTERVAL_IN_MS,
KeyVaultJcaPropertyNames.KEYVAULT_JCA_CERTIFICATES_REFRESH_INTERVAL });
}
}

private void updateKeyStoreConfiguration(KeyVaultLoadStoreParameter parameter) {
refreshCertificatesWhenHaveUnTrustCertificate = parameter.isRefreshCertificatesWhenHaveUnTrustCertificate();
certPathWellKnown = parameter.getCertPathWellKnown();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package com.azure.security.keyvault.jca;

import java.security.KeyStore;
import java.time.Duration;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
Expand Down Expand Up @@ -60,9 +61,9 @@ public final class KeyVaultLoadStoreParameter implements KeyStore.LoadStoreParam
private boolean disableChallengeResourceVerification = false;

/**
* Stores the certificate refresh interval in milliseconds.
* Stores the certificate refresh interval.
*/
private long certificatesRefreshIntervalInMs;
private Duration certificatesRefreshInterval = Duration.ZERO;

/**
* Stores a flag indicating whether AIA certificate downloads are disabled.
Expand Down Expand Up @@ -108,13 +109,17 @@ public static KeyVaultLoadStoreParameter fromSystemProperties() {
parameter.disableChallengeResourceVerification();
}

KeyVaultKeyStore.warnIfRemovedCertificatesRefreshIntervalIsConfigured();
String refreshInterval
= System.getProperty(KeyVaultJcaPropertyNames.KEYVAULT_JCA_CERTIFICATES_REFRESH_INTERVAL_IN_MS);
if (refreshInterval == null) {
refreshInterval = System.getProperty(KeyVaultJcaPropertyNames.KEYVAULT_JCA_CERTIFICATES_REFRESH_INTERVAL);
}
= System.getProperty(KeyVaultJcaPropertyNames.KEYVAULT_JCA_CERTIFICATES_REFRESH_INTERVAL);
if (refreshInterval != null) {
parameter.setCertificatesRefreshIntervalInMs(Long.parseLong(refreshInterval));
Duration interval;
try {
interval = Duration.ofMillis(Long.parseLong(refreshInterval));
} catch (NumberFormatException exception) {
interval = Duration.parse(refreshInterval);
}
parameter.setCertificatesRefreshInterval(interval);
}

if (Boolean.parseBoolean(System.getProperty(KeyVaultJcaPropertyNames.KEYVAULT_JCA_DISABLE_AIA_DOWNLOAD))) {
Expand Down Expand Up @@ -300,22 +305,24 @@ public void disableChallengeResourceVerification() {
}

/**
* Gets the certificate refresh interval in milliseconds.
* Gets the certificate refresh interval.
*
* @return The certificate refresh interval in milliseconds.
* @return The certificate refresh interval. Defaults to {@link Duration#ZERO}, which disables periodic refresh.
*/
public long getCertificatesRefreshIntervalInMs() {
return certificatesRefreshIntervalInMs;
public Duration getCertificatesRefreshInterval() {
return certificatesRefreshInterval;
}

/**
* Sets the certificate refresh interval in milliseconds.
* Sets the certificate refresh interval. Zero or negative intervals disable periodic refresh.
*
* @param certificatesRefreshIntervalInMs The certificate refresh interval in milliseconds.
* @param certificatesRefreshInterval The certificate refresh interval, for example {@code Duration.parse("PT30S")}.
* @return The KeyVaultLoadStoreParameter.
* @throws NullPointerException if {@code certificatesRefreshInterval} is {@code null}.
*/
public KeyVaultLoadStoreParameter setCertificatesRefreshIntervalInMs(long certificatesRefreshIntervalInMs) {
this.certificatesRefreshIntervalInMs = certificatesRefreshIntervalInMs;
public KeyVaultLoadStoreParameter setCertificatesRefreshInterval(Duration certificatesRefreshInterval) {
this.certificatesRefreshInterval
= Objects.requireNonNull(certificatesRefreshInterval, "'certificatesRefreshInterval' cannot be null.");
return this;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ private void updateCertificateConfiguration(KeyVaultLoadStoreParameter parameter
List<Pattern> updatedIncludeAliasPatterns = getAliasPatterns(normalizedFilterPatterns, false);
List<Pattern> updatedExcludeAliasPatterns = getAliasPatterns(normalizedFilterPatterns, true);

certificatesRefreshIntervalInMs = parameter.getCertificatesRefreshIntervalInMs();
certificatesRefreshIntervalInMs = parameter.getCertificatesRefreshInterval().toMillis();
Comment thread
moarychan marked this conversation as resolved.
includeAliasPatterns = updatedIncludeAliasPatterns;
excludeAliasPatterns = updatedExcludeAliasPatterns;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private X509Certificate getTestCertificate() {

@Test
public void testCertificatesRefreshInterval() throws Exception {
System.setProperty(KeyVaultJcaPropertyNames.KEYVAULT_JCA_CERTIFICATES_REFRESH_INTERVAL_IN_MS, "1000");
System.setProperty(KeyVaultJcaPropertyNames.KEYVAULT_JCA_CERTIFICATES_REFRESH_INTERVAL, "PT1S");
KeyStore keyStore = PropertyConvertorUtils.getKeyVaultKeyStore();
assertNotNull(keyStore.getCertificate(certificateName));
keyStore.deleteEntry(certificateName);
Expand Down
Loading
Loading