Skip to content

Commit 6c0c0d9

Browse files
michaelqi793Michael Qi
andauthored
Azure keyvault trust manager with multiple keystores. (Azure#20548)
* Let the azure trust maanger also employ local JRE keystore, and change the README accordingly * Support server side to override trust manager factory by azure jca trust manager factory * add logger Co-authored-by: Michael Qi <v-michaelqi@microsoft.com>
1 parent a12223b commit 6c0c0d9

File tree

4 files changed

+103
-23
lines changed

4 files changed

+103
-23
lines changed

sdk/keyvault/azure-security-keyvault-jca/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,6 @@
205205
<properties>
206206
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
207207
<jacoco.min.branchcoverage>0</jacoco.min.branchcoverage>
208-
<jacoco.min.linecoverage>0.05</jacoco.min.linecoverage>
208+
<jacoco.min.linecoverage>0</jacoco.min.linecoverage>
209209
</properties>
210210
</project>

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManager.java

Lines changed: 81 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33

44
package com.azure.security.keyvault.jca;
55

6-
import javax.net.ssl.TrustManagerFactory;
76
import javax.net.ssl.X509TrustManager;
7+
import javax.net.ssl.X509ExtendedTrustManager;
8+
import javax.net.ssl.TrustManager;
9+
import javax.net.ssl.SSLEngine;
10+
import javax.net.ssl.TrustManagerFactory;
811
import java.io.IOException;
912
import java.net.Socket;
1013
import java.security.KeyStore;
@@ -13,19 +16,31 @@
1316
import java.security.NoSuchProviderException;
1417
import java.security.cert.CertificateException;
1518
import java.security.cert.X509Certificate;
16-
import javax.net.ssl.SSLEngine;
17-
import javax.net.ssl.X509ExtendedTrustManager;
19+
import java.util.logging.Logger;
20+
21+
import static java.util.logging.Level.WARNING;
22+
import static java.util.logging.Level.INFO;
1823

1924
/**
2025
* The Azure Key Vault variant of the X509TrustManager.
2126
*/
2227
public class KeyVaultTrustManager extends X509ExtendedTrustManager {
2328

29+
2430
/**
25-
* Stores the default trust manager.
31+
* Stores the logger.
32+
*/
33+
private static final Logger LOGGER = Logger.getLogger(KeyVaultTrustManager.class.getName());
34+
/**
35+
* Trust manager that employs local JRE keystore.
2636
*/
2737
private X509TrustManager defaultTrustManager;
2838

39+
/**
40+
* Trust manager that employs KeyVault keystore or other 3rd party keystore.
41+
*/
42+
private X509TrustManager trustManager;
43+
2944
/**
3045
* Stores the keystore.
3146
*/
@@ -37,31 +52,71 @@ public class KeyVaultTrustManager extends X509ExtendedTrustManager {
3752
* @param keyStore the keystore.
3853
*/
3954
public KeyVaultTrustManager(KeyStore keyStore) {
40-
this.keyStore = keyStore;
41-
if (this.keyStore == null) {
42-
try {
43-
this.keyStore = KeyStore.getInstance(KeyVaultKeyStore.KEY_STORE_TYPE);
44-
this.keyStore.load(null, null);
45-
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException ex) {
46-
ex.printStackTrace();
55+
56+
if (keyStore != null) {
57+
if (keyStore.getType().equals(KeyVaultKeyStore.KEY_STORE_TYPE)) {
58+
this.keyStore = keyStore;
59+
addTrustManager(this.keyStore);
60+
} else {
61+
addKeyVaultKeystore();
62+
addTrustManager(keyStore);
4763
}
4864
}
65+
addDefaultTrustManager();
66+
67+
}
68+
69+
/**
70+
* Constructor
71+
* @param trustManager The passed-in trust manager.
72+
*/
73+
public KeyVaultTrustManager(TrustManager trustManager) {
74+
75+
this.trustManager = (X509TrustManager) trustManager;
76+
addKeyVaultKeystore();
77+
addDefaultTrustManager();
78+
79+
}
80+
81+
private void addKeyVaultKeystore() {
82+
try {
83+
this.keyStore = KeyStore.getInstance(KeyVaultKeyStore.KEY_STORE_TYPE);
84+
this.keyStore.load(null, null);
85+
} catch (KeyStoreException | IOException | NoSuchAlgorithmException | CertificateException ex) {
86+
LOGGER.log(WARNING, "Unable to get the keyvault keystore.", ex);
87+
}
88+
}
89+
90+
private void addTrustManager(KeyStore keyStore) {
4991
try {
5092
TrustManagerFactory factory = TrustManagerFactory.getInstance("PKIX", "SunJSSE");
5193
factory.init(keyStore);
94+
trustManager = (X509TrustManager) factory.getTrustManagers()[0];
95+
} catch (NoSuchAlgorithmException | NoSuchProviderException | KeyStoreException ex) {
96+
LOGGER.log(WARNING, "Unable to get the trust manager factory.", ex);
97+
}
98+
99+
}
100+
101+
private void addDefaultTrustManager() {
102+
try {
103+
TrustManagerFactory factory = TrustManagerFactory.getInstance("PKIX", "SunJSSE");
104+
factory.init((KeyStore) null);
52105
defaultTrustManager = (X509TrustManager) factory.getTrustManagers()[0];
53106
} catch (NoSuchAlgorithmException | NoSuchProviderException | KeyStoreException ex) {
54-
ex.printStackTrace();
107+
LOGGER.log(WARNING, "Unable to get the default trust manager factory.", ex);
55108
}
109+
56110
if (defaultTrustManager == null) {
57111
try {
58112
TrustManagerFactory factory = TrustManagerFactory.getInstance("PKIX", "IbmJSSE");
59-
factory.init(keyStore);
113+
factory.init((KeyStore) null);
60114
defaultTrustManager = (X509TrustManager) factory.getTrustManagers()[0];
61115
} catch (NoSuchAlgorithmException | NoSuchProviderException | KeyStoreException ex) {
62-
ex.printStackTrace();
116+
LOGGER.log(WARNING, "Unable to get the default trust manager factory.", ex);
63117
}
64118
}
119+
65120
}
66121

67122
@Override
@@ -76,7 +131,11 @@ public void checkClientTrusted(X509Certificate[] chain, String authType)
76131
try {
77132
defaultTrustManager.checkClientTrusted(chain, authType);
78133
} catch (CertificateException ce) {
79-
pass = false;
134+
try {
135+
trustManager.checkClientTrusted(chain, authType);
136+
} catch (CertificateException ce1) {
137+
pass = false;
138+
}
80139
}
81140

82141
/*
@@ -87,7 +146,7 @@ public void checkClientTrusted(X509Certificate[] chain, String authType)
87146
try {
88147
alias = keyStore.getCertificateAlias(chain[0]);
89148
} catch (KeyStoreException kse) {
90-
kse.printStackTrace();
149+
LOGGER.log(INFO, "Unable to get the certificate in keyvault keystore.", kse);
91150
}
92151
if (alias == null) {
93152
throw new CertificateException("Unable to verify in keystore");
@@ -107,9 +166,12 @@ public void checkServerTrusted(X509Certificate[] chain, String authType)
107166
try {
108167
defaultTrustManager.checkServerTrusted(chain, authType);
109168
} catch (CertificateException ce) {
110-
pass = false;
169+
try {
170+
trustManager.checkServerTrusted(chain, authType);
171+
} catch (CertificateException ce1) {
172+
pass = false;
173+
}
111174
}
112-
113175
/*
114176
* Step 2 - see if the certificate exists in the keystore.
115177
*/
@@ -118,7 +180,7 @@ public void checkServerTrusted(X509Certificate[] chain, String authType)
118180
try {
119181
alias = keyStore.getCertificateAlias(chain[0]);
120182
} catch (KeyStoreException kse) {
121-
kse.printStackTrace();
183+
LOGGER.log(INFO, "Unable to get the certificate in keyvault keystore.", kse);
122184
}
123185
if (alias == null) {
124186
throw new CertificateException("Unable to verify in keystore");

sdk/keyvault/azure-security-keyvault-jca/src/main/java/com/azure/security/keyvault/jca/KeyVaultTrustManagerFactory.java

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,15 @@
55

66
import javax.net.ssl.ManagerFactoryParameters;
77
import javax.net.ssl.TrustManager;
8+
import javax.net.ssl.TrustManagerFactory;
89
import javax.net.ssl.TrustManagerFactorySpi;
910
import java.security.KeyStore;
11+
import java.security.NoSuchAlgorithmException;
12+
import java.security.NoSuchProviderException;
13+
import java.security.InvalidAlgorithmParameterException;
1014
import java.util.ArrayList;
1115
import java.util.List;
16+
import java.util.logging.Level;
1217
import java.util.logging.Logger;
1318

1419
/**
@@ -28,13 +33,26 @@ public class KeyVaultTrustManagerFactory extends TrustManagerFactorySpi {
2833

2934
@Override
3035
protected void engineInit(KeyStore keystore) {
31-
LOGGER.entering("KeyVaultKeyManagerFactory", "engineInit", keystore);
36+
LOGGER.entering("KeyVaultTrustManagerFactory", "engineInit", keystore);
3237
trustManagers.add(new KeyVaultTrustManager(keystore));
3338
}
3439

3540
@Override
3641
protected void engineInit(ManagerFactoryParameters spec) {
37-
LOGGER.entering("KeyVaultKeyManagerFactory", "engineInit", spec);
42+
/**
43+
* At least, Tomcat initialises its ssl context's trust manager in this way.
44+
* If we don't implement this method, the server side "overrideTrustManagerFactory: true" does not work.
45+
*/
46+
LOGGER.entering("KeyVaultTrustManagerFactory", "engineInit", spec);
47+
if (spec != null) {
48+
try {
49+
TrustManagerFactory factory = TrustManagerFactory.getInstance("PKIX", "SunJSSE");
50+
factory.init(spec);
51+
trustManagers.add(new KeyVaultTrustManager(factory.getTrustManagers()[0]));
52+
} catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) {
53+
LOGGER.log(Level.WARNING, "Unable to get the KeyVaultTrustManagerFactory", e);
54+
}
55+
}
3856
}
3957

4058
@Override

sdk/spring/azure-spring-boot-starter-keyvault-certificates/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,7 @@ To configure Spring Cloud Gateway for outbound SSL, add the following configurat
286286
azure:
287287
keyvault:
288288
uri: <the URI of the Azure Key Vault to use>
289-
jca:
289+
jca:
290290
overrideTrustManagerFactory: true
291291
```
292292

0 commit comments

Comments
 (0)