@@ -263,6 +263,12 @@ public class HttpRequest {
263
263
*/
264
264
public static final String PARAM_CHARSET = "charset" ;
265
265
266
+ public static final String CERT_MODE_DEFAULT = "default" ;
267
+
268
+ public static final String CERT_MODE_PINNED = "pinned" ;
269
+
270
+ public static final String CERT_MODE_TRUSTALL = "trustall" ;
271
+
266
272
private static final String BOUNDARY = "00content0boundary00" ;
267
273
268
274
private static final String CONTENT_TYPE_MULTIPART = "multipart/form-data; boundary="
@@ -272,13 +278,13 @@ public class HttpRequest {
272
278
273
279
private static final String [] EMPTY_STRINGS = new String [0 ];
274
280
275
- private static SSLSocketFactory PINNED_FACTORY ;
281
+ private static SSLSocketFactory SOCKET_FACTORY ;
276
282
277
- private static SSLSocketFactory TRUSTED_FACTORY ;
283
+ private static String CURRENT_CERT_MODE = CERT_MODE_DEFAULT ;
278
284
279
285
private static ArrayList <Certificate > PINNED_CERTS ;
280
286
281
- private static HostnameVerifier TRUSTED_VERIFIER ;
287
+ private static HostnameVerifier HOSTNAME_VERIFIER ;
282
288
283
289
private static String getValidCharset (final String charset ) {
284
290
if (charset != null && charset .length () > 0 )
@@ -287,63 +293,107 @@ private static String getValidCharset(final String charset) {
287
293
return CHARSET_UTF8 ;
288
294
}
289
295
290
- private static SSLSocketFactory getPinnedFactory ()
291
- throws HttpRequestException {
292
- if (PINNED_FACTORY != null ) {
293
- return PINNED_FACTORY ;
296
+ /**
297
+ * Configure SSL cert handling for all future HTTPS connections
298
+ *
299
+ * @param mode
300
+ */
301
+ public static void setSSLCertMode (String mode ) {
302
+ try {
303
+ if (mode == CERT_MODE_TRUSTALL ) {
304
+ SOCKET_FACTORY = createSocketFactory (getNoopTrustManagers ());
305
+ } else if (mode == CERT_MODE_PINNED ) {
306
+ SOCKET_FACTORY = createSocketFactory (getPinnedTrustManagers ());
307
+ } else {
308
+ SOCKET_FACTORY = null ;
309
+ }
310
+
311
+ CURRENT_CERT_MODE = mode ;
312
+ } catch (IOException e ) {
313
+ throw new HttpRequestException (e );
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Configure host name verification for all future HTTPS connections
319
+ *
320
+ * @param enabled
321
+ */
322
+ public static void setHostnameVerification (boolean enabled ) {
323
+ if (enabled ) {
324
+ HOSTNAME_VERIFIER = null ;
294
325
} else {
295
- IOException e = new IOException ("You must add at least 1 certificate in order to pin to certificates" );
296
- throw new HttpRequestException (e );
326
+ HOSTNAME_VERIFIER = getTrustedVerifier ();
297
327
}
298
328
}
299
329
300
- private static SSLSocketFactory getTrustedFactory ()
301
- throws HttpRequestException {
302
- if ( TRUSTED_FACTORY == null ) {
303
- final TrustManager [] trustAllCerts = new TrustManager [] { new X509TrustManager () {
330
+ private static TrustManager [] getPinnedTrustManagers () throws IOException {
331
+ if ( PINNED_CERTS == null ) {
332
+ throw new IOException ( "You must add at least 1 certificate in order to pin to certificates" );
333
+ }
304
334
305
- public X509Certificate [] getAcceptedIssuers () {
306
- return new X509Certificate [0 ];
307
- }
335
+ try {
336
+ String keyStoreType = KeyStore .getDefaultType ();
337
+ KeyStore keyStore = KeyStore .getInstance (keyStoreType );
338
+ keyStore .load (null , null );
308
339
309
- public void checkClientTrusted ( X509Certificate [] chain , String authType ) {
310
- // Intentionally left blank
311
- }
340
+ for ( int i = 0 ; i < PINNED_CERTS . size (); i ++ ) {
341
+ keyStore . setCertificateEntry ( "CA" + i , PINNED_CERTS . get ( i ));
342
+ }
312
343
313
- public void checkServerTrusted (X509Certificate [] chain , String authType ) {
314
- // Intentionally left blank
315
- }
316
- } };
317
- try {
318
- SSLContext context = SSLContext .getInstance ("TLS" );
319
- context .init (null , trustAllCerts , new SecureRandom ());
344
+ // Create a TrustManager that trusts the CAs in our KeyStore
345
+ String tmfAlgorithm = TrustManagerFactory .getDefaultAlgorithm ();
346
+ TrustManagerFactory tmf = TrustManagerFactory .getInstance (tmfAlgorithm );
347
+ tmf .init (keyStore );
320
348
321
- if (android .os .Build .VERSION .SDK_INT < 20 ) {
322
- TRUSTED_FACTORY = new TLSSocketFactory (context );
323
- } else {
324
- TRUSTED_FACTORY = context .getSocketFactory ();
325
- }
326
- } catch (GeneralSecurityException e ) {
327
- IOException ioException = new IOException (
328
- "Security exception configuring SSL context" );
329
- ioException .initCause (e );
330
- throw new HttpRequestException (ioException );
331
- }
349
+ return tmf .getTrustManagers ();
350
+ } catch (GeneralSecurityException e ) {
351
+ IOException ioException = new IOException ("Security exception configuring SSL trust managers" );
352
+ ioException .initCause (e );
353
+ throw new HttpRequestException (ioException );
332
354
}
355
+ }
356
+
357
+ private static TrustManager [] getNoopTrustManagers () {
358
+ return new TrustManager [] { new X509TrustManager () {
359
+ public X509Certificate [] getAcceptedIssuers () {
360
+ return new X509Certificate [0 ];
361
+ }
333
362
334
- return TRUSTED_FACTORY ;
363
+ public void checkClientTrusted (X509Certificate [] chain , String authType ) {
364
+ // Intentionally left blank
365
+ }
366
+
367
+ public void checkServerTrusted (X509Certificate [] chain , String authType ) {
368
+ // Intentionally left blank
369
+ }
370
+ }};
335
371
}
336
372
337
- private static HostnameVerifier getTrustedVerifier () {
338
- if (TRUSTED_VERIFIER == null )
339
- TRUSTED_VERIFIER = new HostnameVerifier () {
373
+ private static SSLSocketFactory createSocketFactory (TrustManager [] trustManagers )
374
+ throws HttpRequestException {
375
+ try {
376
+ SSLContext context = SSLContext .getInstance ("TLS" );
377
+ context .init (null , trustManagers , new SecureRandom ());
340
378
341
- public boolean verify (String hostname , SSLSession session ) {
342
- return true ;
343
- }
344
- };
379
+ if (android .os .Build .VERSION .SDK_INT < 20 ) {
380
+ return new TLSSocketFactory (context );
381
+ } else {
382
+ return context .getSocketFactory ();
383
+ }
384
+ } catch (GeneralSecurityException e ) {
385
+ IOException ioException = new IOException ("Security exception configuring SSL context" );
386
+ ioException .initCause (e );
387
+ throw new HttpRequestException (ioException );
388
+ }
389
+ }
345
390
346
- return TRUSTED_VERIFIER ;
391
+ private static HostnameVerifier getTrustedVerifier () {
392
+ return new HostnameVerifier () {
393
+ public boolean verify (String hostname , SSLSession session ) {
394
+ return true ;
395
+ }
396
+ };
347
397
}
348
398
349
399
private static StringBuilder addPathSeparator (final String baseUrl ,
@@ -453,32 +503,15 @@ public static void setConnectionFactory(final ConnectionFactory connectionFactor
453
503
* @throws IOException
454
504
*/
455
505
public static void addCert (Certificate ca ) throws GeneralSecurityException , IOException {
456
- if (PINNED_CERTS == null ) {
457
- PINNED_CERTS = new ArrayList <Certificate >();
458
- }
459
- PINNED_CERTS .add (ca );
460
- String keyStoreType = KeyStore .getDefaultType ();
461
- KeyStore keyStore = KeyStore .getInstance (keyStoreType );
462
- keyStore .load (null , null );
463
-
464
- for (int i = 0 ; i < PINNED_CERTS .size (); i ++) {
465
- keyStore .setCertificateEntry ("CA" + i , PINNED_CERTS .get (i ));
466
- }
467
-
468
- // Create a TrustManager that trusts the CAs in our KeyStore
469
- String tmfAlgorithm = TrustManagerFactory .getDefaultAlgorithm ();
470
- TrustManagerFactory tmf = TrustManagerFactory .getInstance (tmfAlgorithm );
471
- tmf .init (keyStore );
506
+ if (PINNED_CERTS == null ) {
507
+ PINNED_CERTS = new ArrayList <Certificate >();
508
+ }
472
509
473
- // Create an SSLContext that uses our TrustManager
474
- SSLContext sslContext = SSLContext .getInstance ("TLS" );
475
- sslContext .init (null , tmf .getTrustManagers (), null );
510
+ PINNED_CERTS .add (ca );
476
511
477
- if (android .os .Build .VERSION .SDK_INT < 20 ) {
478
- PINNED_FACTORY = new TLSSocketFactory (sslContext );
479
- } else {
480
- PINNED_FACTORY = sslContext .getSocketFactory ();
481
- }
512
+ if (CURRENT_CERT_MODE == CERT_MODE_PINNED ) {
513
+ SOCKET_FACTORY = createSocketFactory (getPinnedTrustManagers ());
514
+ }
482
515
}
483
516
484
517
/**
@@ -1632,6 +1665,7 @@ public HttpRequest(final CharSequence url, final String method)
1632
1665
throw new HttpRequestException (e );
1633
1666
}
1634
1667
this .requestMethod = method ;
1668
+ this .setupSecurity ();
1635
1669
}
1636
1670
1637
1671
/**
@@ -1645,6 +1679,23 @@ public HttpRequest(final URL url, final String method)
1645
1679
throws HttpRequestException {
1646
1680
this .url = url ;
1647
1681
this .requestMethod = method ;
1682
+ this .setupSecurity ();
1683
+ }
1684
+
1685
+ private void setupSecurity () {
1686
+ final HttpURLConnection connection = getConnection ();
1687
+
1688
+ if (!(connection instanceof HttpsURLConnection )) {
1689
+ return ;
1690
+ }
1691
+
1692
+ if (SOCKET_FACTORY != null ) {
1693
+ ((HttpsURLConnection ) connection ).setSSLSocketFactory (SOCKET_FACTORY );
1694
+ }
1695
+
1696
+ if (HOSTNAME_VERIFIER != null ) {
1697
+ ((HttpsURLConnection ) connection ).setHostnameVerifier (HOSTNAME_VERIFIER );
1698
+ }
1648
1699
}
1649
1700
1650
1701
private Proxy createProxy () {
@@ -3351,58 +3402,6 @@ public HttpRequest form(final Map<?, ?> values, final String charset)
3351
3402
return this ;
3352
3403
}
3353
3404
3354
- /**
3355
- * Configure HTTPS connection to trust only certain certificates
3356
- * <p>
3357
- * This method throws an exception if the current request is not a HTTPS request
3358
- *
3359
- * @return this request
3360
- * @throws HttpRequestException
3361
- */
3362
- public HttpRequest pinToCerts () throws HttpRequestException {
3363
- final HttpURLConnection connection = getConnection ();
3364
- if (connection instanceof HttpsURLConnection ) {
3365
- ((HttpsURLConnection ) connection ).setSSLSocketFactory (getPinnedFactory ());
3366
- } else {
3367
- IOException e = new IOException ("You must use a https url to use ssl pinning" );
3368
- throw new HttpRequestException (e );
3369
- }
3370
- return this ;
3371
- }
3372
-
3373
- /**
3374
- * Configure HTTPS connection to trust all certificates
3375
- * <p>
3376
- * This method does nothing if the current request is not a HTTPS request
3377
- *
3378
- * @return this request
3379
- * @throws HttpRequestException
3380
- */
3381
- public HttpRequest trustAllCerts () throws HttpRequestException {
3382
- final HttpURLConnection connection = getConnection ();
3383
- if (connection instanceof HttpsURLConnection )
3384
- ((HttpsURLConnection ) connection )
3385
- .setSSLSocketFactory (getTrustedFactory ());
3386
- return this ;
3387
- }
3388
-
3389
- /**
3390
- * Configure HTTPS connection to trust all hosts using a custom
3391
- * {@link HostnameVerifier} that always returns <code>true</code> for each
3392
- * host verified
3393
- * <p>
3394
- * This method does nothing if the current request is not a HTTPS request
3395
- *
3396
- * @return this request
3397
- */
3398
- public HttpRequest trustAllHosts () {
3399
- final HttpURLConnection connection = getConnection ();
3400
- if (connection instanceof HttpsURLConnection )
3401
- ((HttpsURLConnection ) connection )
3402
- .setHostnameVerifier (getTrustedVerifier ());
3403
- return this ;
3404
- }
3405
-
3406
3405
/**
3407
3406
* Get the {@link URL} of this request's connection
3408
3407
*
0 commit comments