@@ -151,7 +151,7 @@ private DatabaseClientFactory.SecurityContext newSecurityContext() {
151
151
}
152
152
final String authType = (String ) typeValue ;
153
153
154
- final SSLInputs sslInputs = buildSSLInputs (authType );
154
+ final SSLUtil . SSLInputs sslInputs = buildSSLInputs (authType );
155
155
DatabaseClientFactory .SecurityContext securityContext = newSecurityContext (authType , sslInputs );
156
156
if (sslInputs .getSslContext () != null ) {
157
157
securityContext .withSSLContext (sslInputs .getSslContext (), sslInputs .getTrustManager ());
@@ -160,7 +160,7 @@ private DatabaseClientFactory.SecurityContext newSecurityContext() {
160
160
return securityContext ;
161
161
}
162
162
163
- private DatabaseClientFactory .SecurityContext newSecurityContext (String type , SSLInputs sslInputs ) {
163
+ private DatabaseClientFactory .SecurityContext newSecurityContext (String type , SSLUtil . SSLInputs sslInputs ) {
164
164
switch (type .toLowerCase ()) {
165
165
case DatabaseClientBuilder .AUTH_TYPE_BASIC :
166
166
return newBasicAuthContext ();
@@ -188,11 +188,15 @@ private String getRequiredStringValue(String propertyName) {
188
188
}
189
189
190
190
private String getNullableStringValue (String propertyName ) {
191
+ return getNullableStringValue (propertyName , null );
192
+ }
193
+
194
+ private String getNullableStringValue (String propertyName , String defaultValue ) {
191
195
Object value = propertySource .apply (PREFIX + propertyName );
192
196
if (value != null && !(value instanceof String )) {
193
197
throw new IllegalArgumentException (propertyName + " must be of type String" );
194
198
}
195
- return (String ) value ;
199
+ return value != null ? (String ) value : defaultValue ;
196
200
}
197
201
198
202
private DatabaseClientFactory .SecurityContext newBasicAuthContext () {
@@ -221,7 +225,7 @@ private DatabaseClientFactory.SecurityContext newCloudAuthContext() {
221
225
return new DatabaseClientFactory .MarkLogicCloudAuthContext (apiKey , duration );
222
226
}
223
227
224
- private DatabaseClientFactory .SecurityContext newCertificateAuthContext (SSLInputs sslInputs ) {
228
+ private DatabaseClientFactory .SecurityContext newCertificateAuthContext (SSLUtil . SSLInputs sslInputs ) {
225
229
String file = getNullableStringValue ("certificate.file" );
226
230
String password = getNullableStringValue ("certificate.password" );
227
231
if (file != null && file .trim ().length () > 0 ) {
@@ -234,6 +238,9 @@ private DatabaseClientFactory.SecurityContext newCertificateAuthContext(SSLInput
234
238
throw new RuntimeException ("Unable to create CertificateAuthContext; cause " + e .getMessage (), e );
235
239
}
236
240
}
241
+ if (sslInputs .getSslContext () == null ) {
242
+ throw new RuntimeException ("An SSLContext is required for certificate authentication." );
243
+ }
237
244
return new DatabaseClientFactory .CertificateAuthContext (sslInputs .getSslContext (), sslInputs .getTrustManager ());
238
245
}
239
246
@@ -271,28 +278,34 @@ private DatabaseClientFactory.SSLHostnameVerifier determineHostnameVerifier() {
271
278
* case the user does not define their own SSLContext or SSL protocol
272
279
* @return
273
280
*/
274
- private SSLInputs buildSSLInputs (String authType ) {
281
+ private SSLUtil . SSLInputs buildSSLInputs (String authType ) {
275
282
X509TrustManager userTrustManager = getTrustManager ();
276
283
277
284
// Approach 1 - user provides an SSLContext object, in which case there's nothing further to check.
278
285
SSLContext sslContext = getSSLContext ();
279
286
if (sslContext != null ) {
280
- return new SSLInputs (sslContext , userTrustManager );
287
+ return new SSLUtil . SSLInputs (sslContext , userTrustManager );
281
288
}
282
289
283
- // Approaches 2 and 3 - user defines an SSL protocol.
284
- // Approach 2 - "default" is a convenience for using the JVM's default SSLContext.
285
- // Approach 3 - create a new SSLContext, and initialize it if the user-provided TrustManager is not null.
290
+ // Approach 2 - user wants two-way SSL via a keystore.
291
+ final String keyStorePath = getNullableStringValue ("ssl.keystore.path" );
292
+ if (keyStorePath != null && keyStorePath .trim ().length () > 0 ) {
293
+ return useKeyStoreForTwoWaySSL (keyStorePath , userTrustManager );
294
+ }
295
+
296
+ // Approaches 3 and 4 - user defines an SSL protocol.
297
+ // Approach 3 - "default" is a convenience for using the JVM's default SSLContext.
298
+ // Approach 4 - create a new SSLContext, and initialize it if the user-provided TrustManager is not null.
286
299
final String sslProtocol = getSSLProtocol (authType );
287
300
if (sslProtocol != null ) {
288
301
return "default" .equalsIgnoreCase (sslProtocol ) ?
289
302
useDefaultSSLContext (userTrustManager ) :
290
303
useNewSSLContext (sslProtocol , userTrustManager );
291
304
}
292
305
293
- // Approach 4 - still return the user-defined TrustManager as that may be needed for certificate authentication,
306
+ // Approach 5 - still return the user-defined TrustManager as that may be needed for certificate authentication,
294
307
// which has its own way of constructing an SSLContext from a PKCS12 file.
295
- return new SSLInputs (null , userTrustManager );
308
+ return new SSLUtil . SSLInputs (null , userTrustManager );
296
309
}
297
310
298
311
private X509TrustManager getTrustManager () {
@@ -332,27 +345,36 @@ private String getSSLProtocol(String authType) {
332
345
return sslProtocol ;
333
346
}
334
347
348
+ private SSLUtil .SSLInputs useKeyStoreForTwoWaySSL (String keyStorePath , X509TrustManager userTrustManager ) {
349
+ final String password = getNullableStringValue ("ssl.keystore.password" );
350
+ final String keyStoreType = getNullableStringValue ("ssl.keystore.type" , "JKS" );
351
+ final String algorithm = getNullableStringValue ("ssl.keystore.algorithm" , "SunX509" );
352
+ final char [] charPassword = password != null ? password .toCharArray () : null ;
353
+ final String sslProtocol = getNullableStringValue ("sslProtocol" , "TLSv1.2" );
354
+ return SSLUtil .createSSLContextFromKeyStore (keyStorePath , charPassword , keyStoreType , algorithm , sslProtocol , userTrustManager );
355
+ }
356
+
335
357
/**
336
358
* Uses the JVM's default SSLContext. Because OkHttp requires a separate TrustManager, this approach will either
337
359
* user the user-provided TrustManager or it will assume that the JVM's default TrustManager should be used.
338
360
*/
339
- private SSLInputs useDefaultSSLContext (X509TrustManager userTrustManager ) {
361
+ private SSLUtil . SSLInputs useDefaultSSLContext (X509TrustManager userTrustManager ) {
340
362
SSLContext sslContext ;
341
363
try {
342
364
sslContext = SSLContext .getDefault ();
343
365
} catch (NoSuchAlgorithmException e ) {
344
366
throw new RuntimeException ("Unable to obtain default SSLContext; cause: " + e .getMessage (), e );
345
367
}
346
368
X509TrustManager trustManager = userTrustManager != null ? userTrustManager : SSLUtil .getDefaultTrustManager ();
347
- return new SSLInputs (sslContext , trustManager );
369
+ return new SSLUtil . SSLInputs (sslContext , trustManager );
348
370
}
349
371
350
372
/**
351
373
* Constructs a new SSLContext based on the given protocol (e.g. TLSv1.2). The SSLContext will be initialized if
352
374
* the user's TrustManager is not null. Otherwise, OkHttpUtil will eventually initialize the SSLContext using the
353
375
* JVM's default TrustManager.
354
376
*/
355
- private SSLInputs useNewSSLContext (String sslProtocol , X509TrustManager userTrustManager ) {
377
+ private SSLUtil . SSLInputs useNewSSLContext (String sslProtocol , X509TrustManager userTrustManager ) {
356
378
SSLContext sslContext ;
357
379
try {
358
380
sslContext = SSLContext .getInstance (sslProtocol );
@@ -368,27 +390,6 @@ private SSLInputs useNewSSLContext(String sslProtocol, X509TrustManager userTrus
368
390
sslProtocol , e .getMessage ()), e );
369
391
}
370
392
}
371
- return new SSLInputs (sslContext , userTrustManager );
372
- }
373
-
374
- /**
375
- * Captures the inputs provided by the caller that pertain to constructing an SSLContext.
376
- */
377
- private static class SSLInputs {
378
- private final SSLContext sslContext ;
379
- private final X509TrustManager trustManager ;
380
-
381
- public SSLInputs (SSLContext sslContext , X509TrustManager trustManager ) {
382
- this .sslContext = sslContext ;
383
- this .trustManager = trustManager ;
384
- }
385
-
386
- public SSLContext getSslContext () {
387
- return sslContext ;
388
- }
389
-
390
- public X509TrustManager getTrustManager () {
391
- return trustManager ;
392
- }
393
+ return new SSLUtil .SSLInputs (sslContext , userTrustManager );
393
394
}
394
395
}
0 commit comments