29
29
import javax .net .ssl .KeyManagerFactory ;
30
30
import javax .net .ssl .TrustManager ;
31
31
import java .io .IOException ;
32
+ import java .io .InputStream ;
33
+ import java .nio .file .Files ;
32
34
import java .nio .file .Paths ;
33
35
import java .security .GeneralSecurityException ;
34
36
import java .security .KeyStore ;
35
37
import java .text .MessageFormat ;
36
- import java .util .Timer ;
37
38
38
39
/**
39
40
* {@link KeyStoresFactory} implementation that reads the certificates from
40
41
* keystore files.
41
42
* <p>
42
- * If either the truststore or the keystore certificates file changes, it
43
- * would be refreshed under the corresponding wrapper implementation -
44
- * {@link ReloadingX509KeystoreManager} or {@link ReloadingX509TrustManager}.
45
- * </p>
43
+ * if the trust certificates keystore file changes, the {@link TrustManager}
44
+ * is refreshed with the new trust certificate entries (using a
45
+ * {@link ReloadingX509TrustManager} trustmanager).
46
46
*/
47
47
@ InterfaceAudience .Private
48
48
@ InterfaceStability .Evolving
@@ -51,13 +51,6 @@ public class FileBasedKeyStoresFactory implements KeyStoresFactory {
51
51
private static final Logger LOG =
52
52
LoggerFactory .getLogger (FileBasedKeyStoresFactory .class );
53
53
54
- /**
55
- * The refresh interval used to check if either of the truststore or keystore
56
- * certificate file has changed.
57
- */
58
- public static final String SSL_STORES_RELOAD_INTERVAL_TPL_KEY =
59
- "ssl.{0}.stores.reload.interval" ;
60
-
61
54
public static final String SSL_KEYSTORE_LOCATION_TPL_KEY =
62
55
"ssl.{0}.keystore.location" ;
63
56
public static final String SSL_KEYSTORE_PASSWORD_TPL_KEY =
@@ -84,119 +77,14 @@ public class FileBasedKeyStoresFactory implements KeyStoresFactory {
84
77
public static final String DEFAULT_KEYSTORE_TYPE = "jks" ;
85
78
86
79
/**
87
- * The default time interval in milliseconds used to check if either
88
- * of the truststore or keystore certificates file has changed and needs reloading.
80
+ * Reload interval in milliseconds.
89
81
*/
90
- public static final int DEFAULT_SSL_STORES_RELOAD_INTERVAL = 10000 ;
82
+ public static final int DEFAULT_SSL_TRUSTSTORE_RELOAD_INTERVAL = 10000 ;
91
83
92
84
private Configuration conf ;
93
85
private KeyManager [] keyManagers ;
94
86
private TrustManager [] trustManagers ;
95
87
private ReloadingX509TrustManager trustManager ;
96
- private Timer fileMonitoringTimer ;
97
-
98
-
99
- private void createTrustManagersFromConfiguration (SSLFactory .Mode mode ,
100
- String truststoreType ,
101
- String truststoreLocation ,
102
- long storesReloadInterval )
103
- throws IOException , GeneralSecurityException {
104
- String passwordProperty = resolvePropertyName (mode ,
105
- SSL_TRUSTSTORE_PASSWORD_TPL_KEY );
106
- String truststorePassword = getPassword (conf , passwordProperty , "" );
107
- if (truststorePassword .isEmpty ()) {
108
- // An empty trust store password is legal; the trust store password
109
- // is only required when writing to a trust store. Otherwise it's
110
- // an optional integrity check.
111
- truststorePassword = null ;
112
- }
113
-
114
- // Check if obsolete truststore specific reload interval is present for backward compatible
115
- long truststoreReloadInterval =
116
- conf .getLong (
117
- resolvePropertyName (mode , SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY ),
118
- storesReloadInterval );
119
-
120
- if (LOG .isDebugEnabled ()) {
121
- LOG .debug (mode .toString () + " TrustStore: " + truststoreLocation +
122
- ", reloading at " + truststoreReloadInterval + " millis." );
123
- }
124
-
125
- trustManager = new ReloadingX509TrustManager (
126
- truststoreType ,
127
- truststoreLocation ,
128
- truststorePassword );
129
-
130
- if (truststoreReloadInterval > 0 ) {
131
- fileMonitoringTimer .schedule (
132
- new FileMonitoringTimerTask (
133
- Paths .get (truststoreLocation ),
134
- path -> trustManager .loadFrom (path ),
135
- exception -> LOG .error (ReloadingX509TrustManager .RELOAD_ERROR_MESSAGE , exception )),
136
- truststoreReloadInterval ,
137
- truststoreReloadInterval );
138
- }
139
-
140
- if (LOG .isDebugEnabled ()) {
141
- LOG .debug (mode .toString () + " Loaded TrustStore: " + truststoreLocation );
142
- }
143
- trustManagers = new TrustManager []{trustManager };
144
- }
145
-
146
- /**
147
- * Implements logic of initializing the KeyManagers with the options
148
- * to reload keystores.
149
- * @param mode client or server
150
- * @param keystoreType The keystore type.
151
- * @param storesReloadInterval The interval to check if the keystore certificates
152
- * file has changed.
153
- */
154
- private void createKeyManagersFromConfiguration (SSLFactory .Mode mode ,
155
- String keystoreType , long storesReloadInterval )
156
- throws GeneralSecurityException , IOException {
157
- String locationProperty =
158
- resolvePropertyName (mode , SSL_KEYSTORE_LOCATION_TPL_KEY );
159
- String keystoreLocation = conf .get (locationProperty , "" );
160
- if (keystoreLocation .isEmpty ()) {
161
- throw new GeneralSecurityException ("The property '" + locationProperty +
162
- "' has not been set in the ssl configuration file." );
163
- }
164
- String passwordProperty =
165
- resolvePropertyName (mode , SSL_KEYSTORE_PASSWORD_TPL_KEY );
166
- String keystorePassword = getPassword (conf , passwordProperty , "" );
167
- if (keystorePassword .isEmpty ()) {
168
- throw new GeneralSecurityException ("The property '" + passwordProperty +
169
- "' has not been set in the ssl configuration file." );
170
- }
171
- String keyPasswordProperty =
172
- resolvePropertyName (mode , SSL_KEYSTORE_KEYPASSWORD_TPL_KEY );
173
- // Key password defaults to the same value as store password for
174
- // compatibility with legacy configurations that did not use a separate
175
- // configuration property for key password.
176
- String keystoreKeyPassword = getPassword (
177
- conf , keyPasswordProperty , keystorePassword );
178
- if (LOG .isDebugEnabled ()) {
179
- LOG .debug (mode .toString () + " KeyStore: " + keystoreLocation );
180
- }
181
-
182
- ReloadingX509KeystoreManager keystoreManager = new ReloadingX509KeystoreManager (
183
- keystoreType ,
184
- keystoreLocation ,
185
- keystorePassword ,
186
- keystoreKeyPassword );
187
-
188
- if (storesReloadInterval > 0 ) {
189
- fileMonitoringTimer .schedule (
190
- new FileMonitoringTimerTask (
191
- Paths .get (keystoreLocation ),
192
- path -> keystoreManager .loadFrom (path ),
193
- exception -> LOG .error (ReloadingX509KeystoreManager .RELOAD_ERROR_MESSAGE , exception )),
194
- storesReloadInterval ,
195
- storesReloadInterval );
196
- }
197
-
198
- keyManagers = new KeyManager [] { keystoreManager };
199
- }
200
88
201
89
/**
202
90
* Resolves a property name to its client/server version if applicable.
@@ -251,28 +139,56 @@ public void init(SSLFactory.Mode mode)
251
139
conf .getBoolean (SSLFactory .SSL_REQUIRE_CLIENT_CERT_KEY ,
252
140
SSLFactory .SSL_REQUIRE_CLIENT_CERT_DEFAULT );
253
141
254
- long storesReloadInterval = conf .getLong (
255
- resolvePropertyName (mode , SSL_STORES_RELOAD_INTERVAL_TPL_KEY ),
256
- DEFAULT_SSL_STORES_RELOAD_INTERVAL );
257
-
258
- fileMonitoringTimer = new Timer ("SSL Certificates Store Monitor" , true );
259
-
260
142
// certificate store
261
143
String keystoreType =
262
- conf .get (resolvePropertyName (mode , SSL_KEYSTORE_TYPE_TPL_KEY ),
263
- DEFAULT_KEYSTORE_TYPE );
264
-
144
+ conf .get (resolvePropertyName (mode , SSL_KEYSTORE_TYPE_TPL_KEY ),
145
+ DEFAULT_KEYSTORE_TYPE );
146
+ KeyStore keystore = KeyStore .getInstance (keystoreType );
147
+ String keystoreKeyPassword = null ;
265
148
if (requireClientCert || mode == SSLFactory .Mode .SERVER ) {
266
- createKeyManagersFromConfiguration (mode , keystoreType , storesReloadInterval );
149
+ String locationProperty =
150
+ resolvePropertyName (mode , SSL_KEYSTORE_LOCATION_TPL_KEY );
151
+ String keystoreLocation = conf .get (locationProperty , "" );
152
+ if (keystoreLocation .isEmpty ()) {
153
+ throw new GeneralSecurityException ("The property '" + locationProperty +
154
+ "' has not been set in the ssl configuration file." );
155
+ }
156
+ String passwordProperty =
157
+ resolvePropertyName (mode , SSL_KEYSTORE_PASSWORD_TPL_KEY );
158
+ String keystorePassword = getPassword (conf , passwordProperty , "" );
159
+ if (keystorePassword .isEmpty ()) {
160
+ throw new GeneralSecurityException ("The property '" + passwordProperty +
161
+ "' has not been set in the ssl configuration file." );
162
+ }
163
+ String keyPasswordProperty =
164
+ resolvePropertyName (mode , SSL_KEYSTORE_KEYPASSWORD_TPL_KEY );
165
+ // Key password defaults to the same value as store password for
166
+ // compatibility with legacy configurations that did not use a separate
167
+ // configuration property for key password.
168
+ keystoreKeyPassword = getPassword (
169
+ conf , keyPasswordProperty , keystorePassword );
170
+ if (LOG .isDebugEnabled ()) {
171
+ LOG .debug (mode .toString () + " KeyStore: " + keystoreLocation );
172
+ }
173
+
174
+ InputStream is = Files .newInputStream (Paths .get (keystoreLocation ));
175
+ try {
176
+ keystore .load (is , keystorePassword .toCharArray ());
177
+ } finally {
178
+ is .close ();
179
+ }
180
+ if (LOG .isDebugEnabled ()) {
181
+ LOG .debug (mode .toString () + " Loaded KeyStore: " + keystoreLocation );
182
+ }
267
183
} else {
268
- KeyStore keystore = KeyStore .getInstance (keystoreType );
269
184
keystore .load (null , null );
270
- KeyManagerFactory keyMgrFactory = KeyManagerFactory
271
- .getInstance (SSLFactory .SSLCERTIFICATE );
272
-
273
- keyMgrFactory .init (keystore , null );
274
- keyManagers = keyMgrFactory .getKeyManagers ();
275
185
}
186
+ KeyManagerFactory keyMgrFactory = KeyManagerFactory
187
+ .getInstance (SSLFactory .SSLCERTIFICATE );
188
+
189
+ keyMgrFactory .init (keystore , (keystoreKeyPassword != null ) ?
190
+ keystoreKeyPassword .toCharArray () : null );
191
+ keyManagers = keyMgrFactory .getKeyManagers ();
276
192
277
193
//trust store
278
194
String truststoreType =
@@ -283,7 +199,33 @@ public void init(SSLFactory.Mode mode)
283
199
resolvePropertyName (mode , SSL_TRUSTSTORE_LOCATION_TPL_KEY );
284
200
String truststoreLocation = conf .get (locationProperty , "" );
285
201
if (!truststoreLocation .isEmpty ()) {
286
- createTrustManagersFromConfiguration (mode , truststoreType , truststoreLocation , storesReloadInterval );
202
+ String passwordProperty = resolvePropertyName (mode ,
203
+ SSL_TRUSTSTORE_PASSWORD_TPL_KEY );
204
+ String truststorePassword = getPassword (conf , passwordProperty , "" );
205
+ if (truststorePassword .isEmpty ()) {
206
+ // An empty trust store password is legal; the trust store password
207
+ // is only required when writing to a trust store. Otherwise it's
208
+ // an optional integrity check.
209
+ truststorePassword = null ;
210
+ }
211
+ long truststoreReloadInterval =
212
+ conf .getLong (
213
+ resolvePropertyName (mode , SSL_TRUSTSTORE_RELOAD_INTERVAL_TPL_KEY ),
214
+ DEFAULT_SSL_TRUSTSTORE_RELOAD_INTERVAL );
215
+
216
+ if (LOG .isDebugEnabled ()) {
217
+ LOG .debug (mode .toString () + " TrustStore: " + truststoreLocation );
218
+ }
219
+
220
+ trustManager = new ReloadingX509TrustManager (truststoreType ,
221
+ truststoreLocation ,
222
+ truststorePassword ,
223
+ truststoreReloadInterval );
224
+ trustManager .init ();
225
+ if (LOG .isDebugEnabled ()) {
226
+ LOG .debug (mode .toString () + " Loaded TrustStore: " + truststoreLocation );
227
+ }
228
+ trustManagers = new TrustManager []{trustManager };
287
229
} else {
288
230
if (LOG .isDebugEnabled ()) {
289
231
LOG .debug ("The property '" + locationProperty + "' has not been set, " +
@@ -314,7 +256,7 @@ String getPassword(Configuration conf, String alias, String defaultPass) {
314
256
@ Override
315
257
public synchronized void destroy () {
316
258
if (trustManager != null ) {
317
- fileMonitoringTimer . cancel ();
259
+ trustManager . destroy ();
318
260
trustManager = null ;
319
261
keyManagers = null ;
320
262
trustManagers = null ;
0 commit comments