certificateKeys = new HashMap<>();
+ private final KeyVaultCertificates keyVaultCertificates;
/**
* Stores the creation date.
@@ -76,13 +75,15 @@ public final class KeyVaultKeyStore extends KeyStoreSpi {
*/
private KeyVaultClient keyVaultClient;
+ private final boolean refreshCertificatesWhenHaveUnTrustCertificate;
+
/**
* Constructor.
*
*
* The constructor uses System.getProperty for
- * azure.keyvault.uri,
- * azure.keyvault.aadAuthenticationUrl,
+ * azure.keyvault.uri,
+ * azure.keyvault.aadAuthenticationUrl,
* azure.keyvault.tenantId,
* azure.keyvault.clientId,
* azure.keyvault.clientSecret and
@@ -102,14 +103,24 @@ public KeyVaultKeyStore() {
} else {
keyVaultClient = new KeyVaultClient(keyVaultUri, managedIdentity);
}
+ long refreshInterval = Optional.ofNullable(System.getProperty("azure.keyvault.jca.certificates-refresh-interval"))
+ .map(Long::valueOf)
+ .orElse(0L);
+ refreshCertificatesWhenHaveUnTrustCertificate = Optional.ofNullable(System.getProperty("azure.keyvault.jca.refresh-certificates-when-have-un-trust-certificate"))
+ .map(Boolean::parseBoolean)
+ .orElse(false);
+ keyVaultCertificates = new KeyVaultCertificates(refreshInterval, keyVaultClient);
+ classpathCertificates = new ClasspathCertificates();
}
@Override
public Enumeration engineAliases() {
- if (aliases == null) {
- aliases = keyVaultClient.getAliases();
- }
- return Collections.enumeration(aliases);
+ List aliasList = Stream.of(keyVaultCertificates, classpathCertificates)
+ .map(AzureCertificates::getAliases)
+ .flatMap(Collection::stream)
+ .distinct().collect(Collectors.toList());
+
+ return Collections.enumeration(aliasList);
}
@Override
@@ -119,6 +130,8 @@ public boolean engineContainsAlias(String alias) {
@Override
public void engineDeleteEntry(String alias) {
+ keyVaultCertificates.deleteEntry(alias);
+ classpathCertificates.deleteEntry(alias);
}
@Override
@@ -128,20 +141,16 @@ public boolean engineEntryInstanceOf(String alias, Class extends KeyStore.Entr
@Override
public Certificate engineGetCertificate(String alias) {
- Certificate certificate;
- if (certificates.containsKey(alias)) {
- certificate = certificates.get(alias);
- } else {
- certificate = keyVaultClient.getCertificate(alias);
- if (certificate != null) {
- certificates.put(alias, certificate);
- if (aliases == null) {
- aliases = keyVaultClient.getAliases();
- }
- if (!aliases.contains(alias)) {
- aliases.add(alias);
- }
- }
+ Certificate certificate = Stream.of(keyVaultCertificates, classpathCertificates)
+ .map(AzureCertificates::getCertificates)
+ .filter(a -> a.containsKey(alias))
+ .findFirst()
+ .map(certificates -> certificates.get(alias))
+ .orElse(null);
+
+ if (refreshCertificatesWhenHaveUnTrustCertificate && certificate == null) {
+ KeyVaultCertificates.updateLastForceRefreshTime();
+ certificate = keyVaultCertificates.getCertificates().get(alias);
}
return certificate;
}
@@ -150,10 +159,13 @@ public Certificate engineGetCertificate(String alias) {
public String engineGetCertificateAlias(Certificate cert) {
String alias = null;
if (cert != null) {
- if (aliases == null) {
- aliases = keyVaultClient.getAliases();
- }
- for (String candidateAlias : aliases) {
+ List aliasList = Stream.of(keyVaultCertificates, classpathCertificates)
+ .map(AzureCertificates::getAliases)
+ .flatMap(Collection::stream)
+ .distinct()
+ .collect(Collectors.toList());
+
+ for (String candidateAlias : aliasList) {
Certificate certificate = engineGetCertificate(candidateAlias);
if (certificate.equals(cert)) {
alias = candidateAlias;
@@ -161,6 +173,9 @@ public String engineGetCertificateAlias(Certificate cert) {
}
}
}
+ if (refreshCertificatesWhenHaveUnTrustCertificate && alias == null) {
+ alias = keyVaultCertificates.refreshAndGetAliasByCertificate(cert);
+ }
return alias;
}
@@ -187,30 +202,21 @@ public KeyStore.Entry engineGetEntry(String alias, KeyStore.ProtectionParameter
@Override
public Key engineGetKey(String alias, char[] password) {
- Key key;
- if (certificateKeys.containsKey(alias)) {
- key = certificateKeys.get(alias);
- } else {
- key = keyVaultClient.getKey(alias, password);
- if (key != null) {
- certificateKeys.put(alias, key);
- if (aliases == null) {
- aliases = keyVaultClient.getAliases();
- }
- if (!aliases.contains(alias)) {
- aliases.add(alias);
- }
- }
- }
- return key;
+ return Stream.of(keyVaultCertificates, classpathCertificates)
+ .map(AzureCertificates::getCertificateKeys)
+ .filter(a -> a.containsKey(alias))
+ .findFirst()
+ .map(certificateKeys -> certificateKeys.get(alias))
+ .orElse(null);
}
@Override
public boolean engineIsCertificateEntry(String alias) {
- if (aliases == null) {
- aliases = keyVaultClient.getAliases();
- }
- return aliases.contains(alias);
+ return Stream.of(keyVaultCertificates, classpathCertificates)
+ .map(AzureCertificates::getAliases)
+ .flatMap(Collection::stream)
+ .distinct()
+ .anyMatch(a -> Objects.equals(a, alias));
}
@Override
@@ -236,24 +242,31 @@ public void engineLoad(KeyStore.LoadStoreParameter param) {
} else {
keyVaultClient = new KeyVaultClient(parameter.getUri());
}
+ keyVaultCertificates.setKeyVaultClient(keyVaultClient);
}
- sideLoad();
+ loadCertificatesFromClasspath();
}
@Override
public void engineLoad(InputStream stream, char[] password) {
- sideLoad();
+ loadCertificatesFromClasspath();
}
@Override
public void engineSetCertificateEntry(String alias, Certificate certificate) {
- if (aliases == null) {
- aliases = keyVaultClient.getAliases();
- }
- if (!aliases.contains(alias)) {
- aliases.add(alias);
- certificates.put(alias, certificate);
+ if (keyVaultCertificates.getAliases().contains(alias)) {
+ return;
}
+ engineSetClasspathCertificateEntry(alias, certificate);
+ }
+
+ /**
+ * Store alias and certificates to Classpath
+ * @param alias Classpath certificate's alias
+ * @param certificate Classpath certificate
+ */
+ public void engineSetClasspathCertificateEntry(String alias, Certificate certificate) {
+ classpathCertificates.setCertificateEntry(alias, certificate);
}
@Override
@@ -271,7 +284,12 @@ public void engineSetKeyEntry(String alias, byte[] key, Certificate[] chain) {
@Override
public int engineSize() {
- return aliases != null ? aliases.size() : 0;
+ return Stream.of(keyVaultCertificates, classpathCertificates)
+ .map(AzureCertificates::getAliases)
+ .flatMap(Collection::stream)
+ .distinct()
+ .collect(Collectors.toList())
+ .size();
}
@Override
@@ -330,7 +348,7 @@ private byte[] readAllBytes(InputStream inputStream) throws IOException {
/**
* Side-load certificate from classpath.
*/
- private void sideLoad() {
+ private void loadCertificatesFromClasspath() {
try {
String[] filenames = getFilenames("/keyvault");
if (filenames.length > 0) {
@@ -346,7 +364,7 @@ private void sideLoad() {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate certificate = (X509Certificate) cf.generateCertificate(
new ByteArrayInputStream(bytes));
- engineSetCertificateEntry(alias, certificate);
+ engineSetClasspathCertificateEntry(alias, certificate);
LOGGER.log(INFO, "Side loaded certificate: {0} from: {1}",
new Object[]{alias, filename});
} catch (CertificateException e) {
diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManager.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManager.java
index 8a40ed8c72cc..6c7083408812 100644
--- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManager.java
+++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManager.java
@@ -39,6 +39,13 @@ public class KeyVaultTrustManager extends X509ExtendedTrustManager {
*/
private KeyStore keyStore;
+ /**
+ * Constructor.
+ */
+ public KeyVaultTrustManager() {
+ this(null);
+ }
+
/**
* Constructor.
*
diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManagerFactory.java b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManagerFactory.java
index 1ac87af72425..6aa7ee23246a 100644
--- a/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManagerFactory.java
+++ b/sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManagerFactory.java
@@ -33,8 +33,10 @@ protected void engineInit(KeyStore keystore) {
}
@Override
+ //TODO: enable create KeyVaultTrustManager with ManagerFactoryParameters
protected void engineInit(ManagerFactoryParameters spec) {
LOGGER.entering("KeyVaultKeyManagerFactory", "engineInit", spec);
+ trustManagers.add(new KeyVaultTrustManager());
}
@Override
diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ClasspathCertificatesTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ClasspathCertificatesTest.java
new file mode 100644
index 000000000000..59b77205f040
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ClasspathCertificatesTest.java
@@ -0,0 +1,46 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.security.keyvault.jca;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.security.Key;
+import java.security.cert.Certificate;
+
+import static org.mockito.Mockito.mock;
+
+public class ClasspathCertificatesTest {
+
+ private Key key = mock(Key.class);
+
+ private Certificate certificate = mock(Certificate.class);
+
+ private ClasspathCertificates classpathCertificates;
+
+ @Test
+ public void testSetCertificateEntry() {
+ classpathCertificates = new ClasspathCertificates();
+ classpathCertificates.setCertificateEntry("myalias", certificate);
+ Assertions.assertTrue(classpathCertificates.getAliases().contains("myalias"));
+ Assertions.assertEquals(classpathCertificates.getCertificates().get("myalias"), certificate);
+ }
+
+ @Test
+ public void testRemoveCertificate() {
+ classpathCertificates = new ClasspathCertificates();
+ classpathCertificates.setCertificateEntry("myalias", certificate);
+ classpathCertificates.removeCertificate("myalias");
+ Assertions.assertNull(classpathCertificates.getCertificates().get("myalias"));
+ }
+
+ @Test
+ public void testRemoveAlias() {
+ classpathCertificates = new ClasspathCertificates();
+ classpathCertificates.setCertificateEntry("myalias", certificate);
+ classpathCertificates.removeAlias("myalias");
+ Assertions.assertFalse(classpathCertificates.getAliases().contains("myalias"));
+ }
+
+}
diff --git a/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultCertificatesTest.java b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultCertificatesTest.java
new file mode 100644
index 000000000000..98af68ebb76c
--- /dev/null
+++ b/sdk/keyvault/azure-security-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultCertificatesTest.java
@@ -0,0 +1,82 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.security.keyvault.jca;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.security.Key;
+import java.security.cert.Certificate;
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class KeyVaultCertificatesTest {
+
+ private final KeyVaultClient keyVaultClient = mock(KeyVaultClient.class);
+
+ private Key key = mock(Key.class);
+
+ private Certificate certificate = mock(Certificate.class);
+
+ private KeyVaultCertificates keyVaultCertificates;
+
+ @BeforeEach
+ public void beforeEach() {
+ List aliases = new ArrayList<>();
+ aliases.add("myalias");
+ when(keyVaultClient.getAliases()).thenReturn(aliases);
+ when(keyVaultClient.getKey("myalias", null)).thenReturn(key);
+ when(keyVaultClient.getCertificate("myalias")).thenReturn(certificate);
+ keyVaultCertificates = new KeyVaultCertificates(0, keyVaultClient);
+ }
+
+ @Test
+ public void testGetAliases() {
+ Assertions.assertTrue(keyVaultCertificates.getAliases().contains("myalias"));
+ }
+
+ @Test
+ public void testGetKey() {
+ Assertions.assertTrue(keyVaultCertificates.getCertificateKeys().containsValue(key));
+ }
+
+ @Test
+ public void testGetCertificate() {
+ Assertions.assertTrue(keyVaultCertificates.getCertificates().containsValue(certificate));
+ }
+
+ @Test
+ public void testRefreshAndGetAliasByCertificate() {
+ Assertions.assertEquals(keyVaultCertificates.refreshAndGetAliasByCertificate(certificate), "myalias");
+ when(keyVaultClient.getAliases()).thenReturn(null);
+ Assertions.assertNotEquals(keyVaultCertificates.refreshAndGetAliasByCertificate(certificate), "myalias");
+ }
+
+ @Test
+ public void testDeleteAlias() {
+ Assertions.assertTrue(keyVaultCertificates.getAliases().contains("myalias"));
+ keyVaultCertificates.deleteEntry("myalias");
+ Assertions.assertFalse(keyVaultCertificates.getAliases().contains("myalias"));
+ }
+
+ @Test
+ public void testCertificatesNeedRefresh() throws InterruptedException {
+ keyVaultCertificates = new KeyVaultCertificates(1000, keyVaultClient);
+ Assertions.assertTrue(keyVaultCertificates.certificatesNeedRefresh());
+ keyVaultCertificates.getAliases();
+ Assertions.assertFalse(keyVaultCertificates.certificatesNeedRefresh());
+ Thread.sleep(10);
+ KeyVaultCertificates.updateLastForceRefreshTime();
+ Assertions.assertTrue(keyVaultCertificates.certificatesNeedRefresh());
+ keyVaultCertificates.getAliases();
+ Assertions.assertFalse(keyVaultCertificates.certificatesNeedRefresh());
+ Thread.sleep(2000);
+ Assertions.assertTrue(keyVaultCertificates.certificatesNeedRefresh());
+ }
+
+}
diff --git a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultCertificatesTest.java b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultCertificatesTest.java
new file mode 100644
index 000000000000..fb9663f1b8a2
--- /dev/null
+++ b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultCertificatesTest.java
@@ -0,0 +1,111 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+package com.azure.security.keyvault.jca;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+
+import java.io.ByteArrayInputStream;
+import java.security.KeyStore;
+import java.security.ProviderException;
+import java.security.Security;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Base64;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+/**
+ * The JUnit test for the KeyVaultCertificates.
+ */
+@EnabledIfEnvironmentVariable(named = "AZURE_KEYVAULT_CERTIFICATE_NAME", matches = "myalias")
+public class KeyVaultCertificatesTest {
+
+ private static String certificateName;
+
+ /**
+ * Stores the CER test certificate (which is valid til 2120).
+ */
+ private static final String TEST_CERTIFICATE
+ = "MIIDeDCCAmCgAwIBAgIQGghBu97rQJKNnUHPWU7xjDANBgkqhkiG9w0BAQsFADAk"
+ + "MSIwIAYDVQQDExlodW5kcmVkLXllYXJzLmV4YW1wbGUuY29tMCAXDTIwMDkwMjE3"
+ + "NDUyNFoYDzIxMjAwOTAyMTc1NTI0WjAkMSIwIAYDVQQDExlodW5kcmVkLXllYXJz"
+ + "LmV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuU14"
+ + "btkN5wmcO2WKXqm1NUKXzi79EtqiFFkrLgPAwj5NNwMw2Akm3GpdEpwkJ8/q3l7d"
+ + "frDEVOO9gwZbz7xppyqutjxjllw8CCgjFdfK02btz56CGgh3X25ZZtzPbuMZJM0j"
+ + "o4mVEdaFNJ0eUeMppS0DcbbuTWCF7Jf1gvr8GVqx+E0IJUFkE+D4kdTbnJSaeK0A"
+ + "KEt94z88MPX18h8ud14uRVmUCYVZrZeswdE2tO1BpazrXELHuXCtrjGxsDDjDzeP"
+ + "98aFI9kblkqoJS4TsmloLEjwZLm80cyJDEmpXXMtR7C0FFXFI1BAtIa4mxSgBLsT"
+ + "L4GVPEGNANR8COYkHQIDAQABo4GjMIGgMA4GA1UdDwEB/wQEAwIFoDAJBgNVHRME"
+ + "AjAAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAkBgNVHREEHTAbghlo"
+ + "dW5kcmVkLXllYXJzLmV4YW1wbGUuY29tMB8GA1UdIwQYMBaAFOGTt4H3ho30O4e+"
+ + "hebwJjm2VMvIMB0GA1UdDgQWBBThk7eB94aN9DuHvoXm8CY5tlTLyDANBgkqhkiG"
+ + "9w0BAQsFAAOCAQEAGp8mCioVCmM+kZv6r+K2j2uog1k4HBwN1NfRoSsibDB8+QXF"
+ + "bmNf3M0imiuR/KJgODyuROwaa/AalxNFMOP8XTL2YmP7XsddBs9ONHHQXKjY/Ojl"
+ + "PsIPR7vZjwYPfEB+XEKl2fOIxDQQ921POBV7M6DdTC49T5X+FsLR1AIIfinVetT9"
+ + "QmNuvzulBX0T0rea/qpcPK4HTj7ToyImOaf8sXRv2s2ODLUrKWu5hhTNH2l6RIkQ"
+ + "U/aIAdQRfDaSE9jhtcVu5d5kCgBs7nz5AzeCisDPo5zIt4Mxej3iVaAJ79oEbHOE"
+ + "p192KLXLV/pscA4Wgb+PJ8AAEa5B6xq8p9JO+Q==";
+
+ @BeforeAll
+ public static void setEnvironmentProperty() {
+ PropertyConvertorUtils.putEnvironmentPropertyToSystemProperty(
+ Arrays.asList("AZURE_KEYVAULT_URI",
+ "AZURE_KEYVAULT_TENANT_ID",
+ "AZURE_KEYVAULT_CLIENT_ID",
+ "AZURE_KEYVAULT_CLIENT_SECRET")
+ );
+ Security.insertProviderAt(new KeyVaultJcaProvider(), 1);
+ certificateName = System.getenv("AZURE_KEYVAULT_CERTIFICATE_NAME");
+ }
+
+ @Test
+ public void testGetKeyStore() throws Exception {
+ KeyStore keyStore = PropertyConvertorUtils.getKeyVaultKeyStore();
+ assertNotNull(keyStore.getCertificate(certificateName));
+ assertTrue(keyStore.containsAlias(certificateName));
+ X509Certificate certificate = getTestCertificate();
+
+ keyStore.setCertificateEntry("setcert", certificate);
+ assertNotNull(keyStore.getCertificateAlias(certificate), "setcert");
+ }
+
+ private X509Certificate getTestCertificate() {
+ X509Certificate certificate;
+
+ try {
+ byte[] certificateBytes = Base64.getDecoder().decode(TEST_CERTIFICATE);
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ certificate = (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(certificateBytes));
+ } catch (CertificateException e) {
+ throw new ProviderException(e);
+ }
+ return certificate;
+ }
+
+ @Test
+ public void testCertificatesRefreshInterval() throws Exception {
+ System.setProperty("azure.keyvault.jca.certificates-refresh-interval", "1000");
+ KeyStore keyStore = PropertyConvertorUtils.getKeyVaultKeyStore();
+ assertNotNull(keyStore.getCertificate(certificateName));
+ keyStore.deleteEntry(certificateName);
+ assertNull(keyStore.getCertificate(certificateName));
+ Thread.sleep(2000);
+ assertNotNull(keyStore.getCertificate(certificateName));
+ }
+
+ @Test
+ public void testUpdateLastForceRefreshTime() throws Exception {
+ KeyStore keyStore = PropertyConvertorUtils.getKeyVaultKeyStore();
+ assertNotNull(keyStore.getCertificate(certificateName));
+ keyStore.deleteEntry(certificateName);
+ assertNull(keyStore.getCertificate(certificateName));
+ Thread.sleep(10);
+ KeyVaultCertificates.updateLastForceRefreshTime();
+ assertNotNull(keyStore.getCertificate(certificateName));
+ }
+}
diff --git a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultJcaProviderTest.java b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultJcaProviderTest.java
index 17ca799bd4cf..2d52b338574f 100644
--- a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultJcaProviderTest.java
+++ b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultJcaProviderTest.java
@@ -33,13 +33,7 @@ public void testGetCertificate() throws Exception {
"AZURE_KEYVAULT_CLIENT_SECRET")
);
Security.addProvider(new KeyVaultJcaProvider());
- KeyStore keystore = KeyStore.getInstance("AzureKeyVault");
- KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
- System.getenv("AZURE_KEYVAULT_URI"),
- System.getenv("AZURE_KEYVAULT_TENANT_ID"),
- System.getenv("AZURE_KEYVAULT_CLIENT_ID"),
- System.getenv("AZURE_KEYVAULT_CLIENT_SECRET"));
- keystore.load(parameter);
+ KeyStore keystore = PropertyConvertorUtils.getKeyVaultKeyStore();
assertNotNull(keystore.getCertificate(System.getenv("AZURE_KEYVAULT_CERTIFICATE_NAME")));
}
}
diff --git a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyManagerTest.java b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyManagerTest.java
index a79e16534862..dc3229b1dcc9 100644
--- a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyManagerTest.java
+++ b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyManagerTest.java
@@ -33,13 +33,7 @@ public static void setEnvironmentProperty() throws KeyStoreException, NoSuchAlgo
"AZURE_KEYVAULT_CLIENT_SECRET")
);
Security.insertProviderAt(new KeyVaultJcaProvider(), 1);
- KeyStore keyStore = KeyStore.getInstance("AzureKeyVault");
- KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
- System.getenv("AZURE_KEYVAULT_URI"),
- System.getenv("AZURE_KEYVAULT_TENANT_ID"),
- System.getenv("AZURE_KEYVAULT_CLIENT_ID"),
- System.getenv("AZURE_KEYVAULT_CLIENT_SECRET"));
- keyStore.load(parameter);
+ KeyStore keyStore = PropertyConvertorUtils.getKeyVaultKeyStore();
manager = new KeyVaultKeyManager(keyStore, null);
certificateName = System.getenv("AZURE_KEYVAULT_CERTIFICATE_NAME");
}
diff --git a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyStoreTest.java b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyStoreTest.java
index 47b910102e62..f2a18a9dba6c 100644
--- a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyStoreTest.java
+++ b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/KeyVaultKeyStoreTest.java
@@ -8,15 +8,17 @@
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
import java.io.ByteArrayInputStream;
+import java.security.KeyStore;
import java.security.ProviderException;
+import java.security.Security;
+import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Base64;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
/**
* The JUnit tests for the KeyVaultKeyStore class.
@@ -141,7 +143,9 @@ public void testEngineGetCreationDate() {
@Test
public void testEngineDeleteEntry() {
KeyVaultKeyStore keystore = new KeyVaultKeyStore();
+ assertTrue(keystore.engineContainsAlias(certificateName));
keystore.engineDeleteEntry(certificateName);
+ assertFalse(keystore.engineContainsAlias(certificateName));
}
@Test
@@ -155,4 +159,27 @@ public void testEngineStore() {
KeyVaultKeyStore keystore = new KeyVaultKeyStore();
keystore.engineStore(null, null);
}
+
+ @Test
+ public void testRefreshEngineGetCertificate() throws Exception {
+ System.setProperty("azure.keyvault.jca.refresh-certificates-when-have-un-trust-certificate", "true");
+ KeyVaultJcaProvider provider = new KeyVaultJcaProvider();
+ Security.addProvider(provider);
+ KeyStore ks = PropertyConvertorUtils.getKeyVaultKeyStore();
+ Certificate certificate = ks.getCertificate(certificateName);
+ ks.deleteEntry(certificateName);
+ Thread.sleep(10);
+ assertEquals(ks.getCertificateAlias(certificate), certificateName);
+ }
+
+ @Test
+ public void testNotRefreshEngineGetCertificate() throws Exception {
+ KeyVaultJcaProvider provider = new KeyVaultJcaProvider();
+ Security.addProvider(provider);
+ KeyStore ks = PropertyConvertorUtils.getKeyVaultKeyStore();
+ Certificate certificate = ks.getCertificate(certificateName);
+ ks.deleteEntry(certificateName);
+ assertNull(ks.getCertificateAlias(certificate));
+ }
+
}
diff --git a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/PropertyConvertorUtils.java b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/PropertyConvertorUtils.java
index d9da4bea8829..0e960acfb906 100644
--- a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/PropertyConvertorUtils.java
+++ b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/PropertyConvertorUtils.java
@@ -3,6 +3,12 @@
package com.azure.security.keyvault.jca;
+import java.io.IOException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.CertificateException;
+import java.util.Arrays;
import java.util.List;
public class PropertyConvertorUtils {
@@ -17,4 +23,21 @@ public static void putEnvironmentPropertyToSystemProperty(List key) {
}
);
}
+
+ public static final List SYSTEM_PROPERTIES = Arrays.asList("AZURE_KEYVAULT_URI",
+ "AZURE_KEYVAULT_TENANT_ID",
+ "AZURE_KEYVAULT_CLIENT_ID",
+ "AZURE_KEYVAULT_CLIENT_SECRET");
+
+ public static KeyStore getKeyVaultKeyStore() throws CertificateException, NoSuchAlgorithmException, IOException, KeyStoreException {
+ KeyStore keyStore = KeyStore.getInstance("AzureKeyVault");
+ KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
+ System.getenv("AZURE_KEYVAULT_URI"),
+ System.getenv("AZURE_KEYVAULT_TENANT_ID"),
+ System.getenv("AZURE_KEYVAULT_CLIENT_ID"),
+ System.getenv("AZURE_KEYVAULT_CLIENT_SECRET"));
+ keyStore.load(parameter);
+ return keyStore;
+ }
+
}
diff --git a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ServerSocketTest.java b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ServerSocketTest.java
index 86ce286199f0..7409c0856acf 100644
--- a/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ServerSocketTest.java
+++ b/sdk/keyvault/azure-security-test-keyvault-jca/src/test/java/com/azure/security/keyvault/jca/ServerSocketTest.java
@@ -13,14 +13,15 @@
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
+import org.apache.http.ssl.PrivateKeyDetails;
+import org.apache.http.ssl.PrivateKeyStrategy;
import org.apache.http.ssl.SSLContexts;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
-import javax.net.ssl.KeyManagerFactory;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLServerSocket;
-import javax.net.ssl.SSLServerSocketFactory;
+import javax.net.ssl.*;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
@@ -28,23 +29,25 @@
import java.security.Security;
import java.security.cert.X509Certificate;
import java.util.Arrays;
+import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
/**
* The unit test validating the ServerSocket is created using a certificate from Azure Key Vault.
*/
+@Disabled("Block live test, disable temporarily")
@EnabledIfEnvironmentVariable(named = "AZURE_KEYVAULT_CERTIFICATE_NAME", matches = "myalias")
public class ServerSocketTest {
+ private static KeyStore ks;
- /**
- * Test SSLServerSocket without client trust.
- *
- * @throws Exception when a serious error occurs.
- */
- @Test
- public void testServerSocket() throws Exception {
+ private static KeyManagerFactory kmf;
+
+ private static String certificateName;
+
+ @BeforeAll
+ public static void beforeEach() throws Exception {
/*
* Add JCA provider.
@@ -52,37 +55,26 @@ public void testServerSocket() throws Exception {
KeyVaultJcaProvider provider = new KeyVaultJcaProvider();
Security.addProvider(provider);
- /*
- * Setup server side.
- *
- * - Create an Azure Key Vault specific instance of a KeyStore.
- * - Set the KeyManagerFactory to use that KeyStore.
- * - Set the SSL context to use the KeyManagerFactory.
- * - Create the SSLServerSocket using th SSL context.
- */
PropertyConvertorUtils.putEnvironmentPropertyToSystemProperty(
Arrays.asList("AZURE_KEYVAULT_URI",
"AZURE_KEYVAULT_TENANT_ID",
"AZURE_KEYVAULT_CLIENT_ID",
"AZURE_KEYVAULT_CLIENT_SECRET")
);
- KeyStore ks = KeyStore.getInstance("AzureKeyVault");
- KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
- System.getenv("AZURE_KEYVAULT_URI"),
- System.getenv("AZURE_KEYVAULT_TENANT_ID"),
- System.getenv("AZURE_KEYVAULT_CLIENT_ID"),
- System.getenv("AZURE_KEYVAULT_CLIENT_SECRET"));
- ks.load(parameter);
-
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+
+ /**
+ * - Create an Azure Key Vault specific instance of a KeyStore.
+ * - Set the KeyManagerFactory to use that KeyStore.
+ */
+ ks = PropertyConvertorUtils.getKeyVaultKeyStore();
+ kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(ks, "".toCharArray());
- SSLContext context = SSLContext.getInstance("TLS");
- context.init(kmf.getKeyManagers(), null, null);
+ certificateName = System.getenv("AZURE_KEYVAULT_CERTIFICATE_NAME");
+ }
- SSLServerSocketFactory factory = context.getServerSocketFactory();
- SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(8765);
+ private void startSocket(SSLServerSocket serverSocket) {
Thread server = new Thread(() -> {
while (true) {
try {
@@ -97,129 +89,124 @@ public void testServerSocket() throws Exception {
}
});
server.start();
+ }
- /*
- * Setup client side
- *
- * - Create an SSL context.
- * - Set SSL context to trust any certificate.
- * - Create SSL connection factory.
- * - Set hostname verifier to trust any hostname.
- */
-
+ @Test
+ public void testHttpsConnectionWithoutClientTrust() throws Exception {
SSLContext sslContext = SSLContexts
.custom()
.loadTrustMaterial((final X509Certificate[] chain, final String authType) -> true)
.build();
+ testHttpsConnection(8765, sslContext);
- SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
- sslContext, (hostname, session) -> true);
-
- PoolingHttpClientConnectionManager manager = new PoolingHttpClientConnectionManager(
- RegistryBuilder.create()
- .register("https", sslConnectionSocketFactory)
- .build());
+ }
- /*
- * And now execute the test.
- */
- String result = null;
+ @Test
+ public void testHttpsConnectionWithSelfSignedClientTrust() throws Exception {
+ SSLContext sslContext = SSLContexts
+ .custom()
+ .loadTrustMaterial(ks, new TrustSelfSignedStrategy())
+ .build();
+ testHttpsConnection(8766, sslContext);
- try (CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).build()) {
- HttpGet httpGet = new HttpGet("https://localhost:8765");
- ResponseHandler responseHandler = (HttpResponse response) -> {
- int status = response.getStatusLine().getStatusCode();
- String result1 = null;
- if (status == 204) {
- result1 = "Success";
- }
- return result1;
- };
- result = client.execute(httpGet, responseHandler);
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
+ }
- /*
- * And verify all went well.
- */
- assertEquals("Success", result);
+ @Test
+ public void testServerSocketWithDefaultTrustManager() throws Exception {
+ serverSocketWithTrustManager(8768);
}
+
/**
- * Test SSLServerSocket WITH self-signed client trust.
+ * Test SSLServerSocket with key vault trust manager.
*
* @throws Exception when a serious error occurs.
*/
@Test
- public void testServerSocketWithSelfSignedClientTrust() throws Exception {
+ public void testServerSocketWithKeyVaultTrustManager() throws Exception {
+ Security.insertProviderAt(new KeyVaultTrustManagerFactoryProvider(), 1);
+ serverSocketWithTrustManager(8767);
+ }
+
+
+ private void testHttpsConnection(Integer port, SSLContext sslContext) throws Exception {
/*
- * Add JCA provider.
+ * Setup server side.
+ *
+ * - Set the SSL context to use the KeyManagerFactory.
+ * - Create the SSLServerSocket using th SSL context.
*/
- KeyVaultJcaProvider provider = new KeyVaultJcaProvider();
- Security.addProvider(provider);
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(kmf.getKeyManagers(), null, null);
+
+ SSLServerSocketFactory factory = context.getServerSocketFactory();
+ SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(port);
+
+ startSocket(serverSocket);
+
+ /*
+ * And now execute the test.
+ */
+ String result = sendRequest(sslContext, port);
+
+ /*
+ * And verify all went well.
+ */
+ assertEquals("Success", result);
+ }
+
+ private void serverSocketWithTrustManager(Integer port) throws Exception {
/*
* Setup server side.
*
- * - Create an Azure Key Vault specific instance of a KeyStore.
- * - Set the KeyManagerFactory to use that KeyStore.
* - Set the SSL context to use the KeyManagerFactory.
* - Create the SSLServerSocket using th SSL context.
*/
- PropertyConvertorUtils.putEnvironmentPropertyToSystemProperty(
- Arrays.asList("AZURE_KEYVAULT_URI",
- "AZURE_KEYVAULT_TENANT_ID",
- "AZURE_KEYVAULT_CLIENT_ID",
- "AZURE_KEYVAULT_CLIENT_SECRET")
- );
- KeyStore ks = KeyStore.getInstance("AzureKeyVault");
- KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
- System.getenv("AZURE_KEYVAULT_URI"),
- System.getenv("AZURE_KEYVAULT_TENANT_ID"),
- System.getenv("AZURE_KEYVAULT_CLIENT_ID"),
- System.getenv("AZURE_KEYVAULT_CLIENT_SECRET"));
- ks.load(parameter);
-
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
- kmf.init(ks, "".toCharArray());
+
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(ks);
SSLContext context = SSLContext.getInstance("TLS");
- context.init(kmf.getKeyManagers(), null, null);
+ context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
SSLServerSocketFactory factory = context.getServerSocketFactory();
- SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(8766);
+ SSLServerSocket serverSocket = (SSLServerSocket) factory.createServerSocket(port);
+ serverSocket.setNeedClientAuth(true);
- Thread server = new Thread(() -> {
- while (true) {
- try {
- Socket socket = serverSocket.accept();
- try (OutputStream outputStream = socket.getOutputStream()) {
- outputStream.write("HTTP/1.1 204\r\n".getBytes());
- outputStream.flush();
- }
- } catch (IOException ioe) {
- ioe.printStackTrace();
- }
- }
- });
- server.start();
+ startSocket(serverSocket);
/*
* Setup client side
*
* - Create an SSL context.
* - Set SSL context to trust any certificate.
- * - Create SSL connection factory.
- * - Set hostname verifier to trust any hostname.
*/
SSLContext sslContext = SSLContexts
.custom()
.loadTrustMaterial(ks, new TrustSelfSignedStrategy())
+ .loadKeyMaterial(ks, "".toCharArray(), new ClientPrivateKeyStrategy())
.build();
+ /*
+ * And now execute the test.
+ */
+ String result = sendRequest(sslContext, port);
+
+ /*
+ * And verify all went well.
+ */
+ assertEquals("Success", result);
+ }
+
+ private String sendRequest(SSLContext sslContext, Integer port) {
+
+ /**
+ * - Create SSL connection factory.
+ * - Set hostname verifier to trust any hostname.
+ */
SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(
sslContext, (hostname, session) -> true);
@@ -228,13 +215,11 @@ public void testServerSocketWithSelfSignedClientTrust() throws Exception {
.register("https", sslConnectionSocketFactory)
.build());
- /*
- * And now execute the test.
- */
+
String result = null;
try (CloseableHttpClient client = HttpClients.custom().setConnectionManager(manager).build()) {
- HttpGet httpGet = new HttpGet("https://localhost:8766");
+ HttpGet httpGet = new HttpGet("https://localhost:" + port);
ResponseHandler responseHandler = (HttpResponse response) -> {
int status = response.getStatusLine().getStatusCode();
String result1 = null;
@@ -247,10 +232,15 @@ public void testServerSocketWithSelfSignedClientTrust() throws Exception {
} catch (IOException ioe) {
ioe.printStackTrace();
}
+ return result;
+ }
- /*
- * And verify all went well.
- */
- assertEquals("Success", result);
+
+ private static class ClientPrivateKeyStrategy implements PrivateKeyStrategy {
+ @Override
+ public String chooseAlias(Map map, Socket socket) {
+ return certificateName; // It should be your certificate alias used in client-side
+ }
}
+
}
diff --git a/sdk/spring/azure-spring-boot-samples/azure-spring-boot-sample-keyvault-certificates-client-side/src/main/java/com/azure/spring/security/keyvault/certificates/sample/client/side/SampleApplicationConfiguration.java b/sdk/spring/azure-spring-boot-samples/azure-spring-boot-sample-keyvault-certificates-client-side/src/main/java/com/azure/spring/security/keyvault/certificates/sample/client/side/SampleApplicationConfiguration.java
index 5ba9a58d5d4a..bdb3d14db1e1 100644
--- a/sdk/spring/azure-spring-boot-samples/azure-spring-boot-sample-keyvault-certificates-client-side/src/main/java/com/azure/spring/security/keyvault/certificates/sample/client/side/SampleApplicationConfiguration.java
+++ b/sdk/spring/azure-spring-boot-samples/azure-spring-boot-sample-keyvault-certificates-client-side/src/main/java/com/azure/spring/security/keyvault/certificates/sample/client/side/SampleApplicationConfiguration.java
@@ -24,15 +24,15 @@ public class SampleApplicationConfiguration {
@Bean
public RestTemplate restTemplateWithTLS() throws Exception {
- KeyStore trustStore = KeyStore.getInstance("AzureKeyVault");
+ KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
System.getProperty("azure.keyvault.uri"),
System.getProperty("azure.keyvault.tenant-id"),
System.getProperty("azure.keyvault.client-id"),
System.getProperty("azure.keyvault.client-secret"));
- trustStore.load(parameter);
+ azureKeyVaultKeyStore.load(parameter);
SSLContext sslContext = SSLContexts.custom()
- .loadTrustMaterial(trustStore, null)
+ .loadTrustMaterial(azureKeyVaultKeyStore, null)
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,
(hostname, session) -> true);
@@ -46,16 +46,16 @@ public RestTemplate restTemplateWithTLS() throws Exception {
@Bean
public RestTemplate restTemplateWithMTLS() throws Exception {
- KeyStore azuerKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
+ KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
System.getProperty("azure.keyvault.uri"),
System.getProperty("azure.keyvault.tenant-id"),
System.getProperty("azure.keyvault.client-id"),
System.getProperty("azure.keyvault.client-secret"));
- azuerKeyVaultKeyStore.load(parameter);
+ azureKeyVaultKeyStore.load(parameter);
SSLContext sslContext = SSLContexts.custom()
- .loadTrustMaterial(azuerKeyVaultKeyStore, null)
- .loadKeyMaterial(azuerKeyVaultKeyStore, "".toCharArray(), new ClientPrivateKeyStrategy())
+ .loadTrustMaterial(azureKeyVaultKeyStore, null)
+ .loadKeyMaterial(azureKeyVaultKeyStore, "".toCharArray(), new ClientPrivateKeyStrategy())
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,
(hostname, session) -> true);
diff --git a/sdk/spring/azure-spring-boot-starter-keyvault-certificates/README.md b/sdk/spring/azure-spring-boot-starter-keyvault-certificates/README.md
index 43f2475a92dc..f51b1bcf7687 100644
--- a/sdk/spring/azure-spring-boot-starter-keyvault-certificates/README.md
+++ b/sdk/spring/azure-spring-boot-starter-keyvault-certificates/README.md
@@ -174,15 +174,15 @@ Configure a `RestTemplate` bean which set the `AzureKeyVault` as trust store:
```java
@Bean
public RestTemplate restTemplateWithTLS() throws Exception {
- KeyStore trustStore = KeyStore.getInstance("AzureKeyVault");
+ KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
System.getProperty("azure.keyvault.uri"),
System.getProperty("azure.keyvault.tenant-id"),
System.getProperty("azure.keyvault.client-id"),
System.getProperty("azure.keyvault.client-secret"));
- trustStore.load(parameter);
+ azureKeyVaultKeyStore.load(parameter);
SSLContext sslContext = SSLContexts.custom()
- .loadTrustMaterial(trustStore, null)
+ .loadTrustMaterial(azureKeyVaultKeyStore, null)
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,
(hostname, session) -> true);
@@ -249,16 +249,16 @@ Step 2. On the client side, update `RestTemplate`. Example:
```java
@Bean
public RestTemplate restTemplateWithMTLS() throws Exception {
- KeyStore azuerKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
+ KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault");
KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter(
System.getProperty("azure.keyvault.uri"),
System.getProperty("azure.keyvault.tenant-id"),
System.getProperty("azure.keyvault.client-id"),
System.getProperty("azure.keyvault.client-secret"));
- azuerKeyVaultKeyStore.load(parameter);
+ azureKeyVaultKeyStore.load(parameter);
SSLContext sslContext = SSLContexts.custom()
- .loadTrustMaterial(azuerKeyVaultKeyStore, null)
- .loadKeyMaterial(azuerKeyVaultKeyStore, "".toCharArray(), new ClientPrivateKeyStrategy())
+ .loadTrustMaterial(azureKeyVaultKeyStore, null)
+ .loadKeyMaterial(azureKeyVaultKeyStore, "".toCharArray(), new ClientPrivateKeyStrategy())
.build();
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,
(hostname, session) -> true);
@@ -316,6 +316,41 @@ spring:
useInsecureTrustManager: true
```
+### Refresh certificates when have un trust certificate
+
+When the inbound certificate is not trusted, the KeyVaultKeyStore can fetch
+certificates from KeyVault if the following property is configured:
+
+```yaml
+azure:
+ keyvault:
+ jca:
+ refresh-certificates-when-have-un-trust-certificate: true
+```
+
+Note: If you set refresh-certificates-when-have-un-trust-certificate=true, your server will be vulnerable
+to attack, because every untrusted certificate will cause your application to send a re-acquire certificate request.
+
+### Refresh certificate periodically
+
+KeyVaultKeyStore can fetch certificates from KeyVault periodically if following property is configured:
+
+```yaml
+azure:
+ keyvault:
+ jca:
+ certificates-refresh-interval: 1800000
+```
+
+Its value is 0(ms) by default, and certificate will not automatically refresh when its value <= 0.
+
+### Refresh certificate by java code
+
+You can also manually refresh the certificate by calling this method:
+```java
+KeyVaultCertificates.refreshCertsInfo();
+```
+
### Side-loading certificates
This starter allows you to side-load certificates by supplying them as part of
diff --git a/sdk/spring/azure-spring-boot-starter-keyvault-certificates/src/main/java/com/azure/spring/security/keyvault/certificates/starter/KeyVaultCertificatesEnvironmentPostProcessor.java b/sdk/spring/azure-spring-boot-starter-keyvault-certificates/src/main/java/com/azure/spring/security/keyvault/certificates/starter/KeyVaultCertificatesEnvironmentPostProcessor.java
index 5c750615a621..6d20b6e68105 100644
--- a/sdk/spring/azure-spring-boot-starter-keyvault-certificates/src/main/java/com/azure/spring/security/keyvault/certificates/starter/KeyVaultCertificatesEnvironmentPostProcessor.java
+++ b/sdk/spring/azure-spring-boot-starter-keyvault-certificates/src/main/java/com/azure/spring/security/keyvault/certificates/starter/KeyVaultCertificatesEnvironmentPostProcessor.java
@@ -37,6 +37,8 @@ public void postProcessEnvironment(ConfigurableEnvironment environment, SpringAp
putEnvironmentPropertyToSystemProperty(environment, "azure.keyvault.client-id");
putEnvironmentPropertyToSystemProperty(environment, "azure.keyvault.client-secret");
putEnvironmentPropertyToSystemProperty(environment, "azure.keyvault.managed-identity");
+ putEnvironmentPropertyToSystemProperty(environment, "azure.keyvault.jca.certificates-refresh-interval");
+ putEnvironmentPropertyToSystemProperty(environment, "azure.keyvault.jca.refresh-certificates-when-have-un-trust-certificate");
MutablePropertySources propertySources = environment.getPropertySources();
if (KeyVaultKeyStore.KEY_STORE_TYPE.equals(environment.getProperty("server.ssl.key-store-type"))) {
diff --git a/sdk/spring/azure-spring-boot-starter-keyvault-certificates/src/main/java/com/azure/spring/security/keyvault/certificates/starter/KeyVaultProperties.java b/sdk/spring/azure-spring-boot-starter-keyvault-certificates/src/main/java/com/azure/spring/security/keyvault/certificates/starter/KeyVaultProperties.java
index e37693550151..1c485c0a1ec1 100644
--- a/sdk/spring/azure-spring-boot-starter-keyvault-certificates/src/main/java/com/azure/spring/security/keyvault/certificates/starter/KeyVaultProperties.java
+++ b/sdk/spring/azure-spring-boot-starter-keyvault-certificates/src/main/java/com/azure/spring/security/keyvault/certificates/starter/KeyVaultProperties.java
@@ -91,11 +91,36 @@ public static class JcaProperties {
* To configure Spring Cloud Gateway for outbound SSL, set overrideTrustManagerFactory = true.
*/
private String overrideTrustManagerFactory;
+ /**
+ * To configure refresh certificate when get untrusted certificate.
+ */
+ private String refreshCertificatesWhenHaveUnTrustCertificate;
+
+ public String getRefreshCertificatesWhenHaveUnTrustCertificate() {
+ return refreshCertificatesWhenHaveUnTrustCertificate;
+ }
+
+ public void setRefreshCertificatesWhenHaveUnTrustCertificate(String refreshCertificatesWhenHaveUnTrustCertificate) {
+ this.refreshCertificatesWhenHaveUnTrustCertificate = refreshCertificatesWhenHaveUnTrustCertificate;
+ }
+
/**
* If you are developing you can completely disable the certificate and hostname validation altogether by
* setting disableHostnameVerification = true. Note: this is NOT recommended for production!
*/
private String disableHostnameVerification;
+ /**
+ * To enable auto refresh certificate, set certificatesRefreshInterval as refresh interval. The unit of time is milliseconds.
+ */
+ private long certificatesRefreshInterval;
+
+ public long getCertificatesRefreshInterval() {
+ return certificatesRefreshInterval;
+ }
+
+ public void setCertificatesRefreshInterval(long certificatesRefreshInterval) {
+ this.certificatesRefreshInterval = certificatesRefreshInterval;
+ }
public String getOverrideTrustManagerFactory() {
return overrideTrustManagerFactory;