You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by gg...@apache.org on 2021/10/10 18:36:09 UTC

[httpcomponents-core] branch master updated: Add SSLContextBuilder NIO Path versions of IO File APIs and re-implement internals with NIO. (#301)

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-core.git


The following commit(s) were added to refs/heads/master by this push:
     new 6f6a4a2  Add SSLContextBuilder NIO Path versions of IO File APIs and re-implement internals with NIO. (#301)
6f6a4a2 is described below

commit 6f6a4a2e55e0aac36414ab2e14397703f1c4cbc6
Author: Gary Gregory <ga...@users.noreply.github.com>
AuthorDate: Sun Oct 10 14:36:05 2021 -0400

    Add SSLContextBuilder NIO Path versions of IO File APIs and re-implement internals with NIO. (#301)
    
    * Add SSLContextBuilder NIO Path versions of IO File APIs and re-implement
    internals with NIO.
    
    Using NIO, we no longer create FileInputStream instances which required
    finalization from the JVM.
    
    * Clean ups.
    
    - Remove redundant calls to super().
    - Reduce duplication.
    - Camel-case parameter names.
    - Use {} notation.
    
    * Update JApiCmp 0.15.3 -> 0.15.4 and use a property to tack its
    version.
    
    Co-authored-by: Gary Gregory <gg...@rocketsoftware.com>
---
 .../apache/hc/core5/benchmark/HttpBenchmark.java   |   3 +-
 .../org/apache/hc/core5/ssl/SSLContextBuilder.java | 159 ++++++++++++++-------
 pom.xml                                            |   5 +-
 3 files changed, 111 insertions(+), 56 deletions(-)

diff --git a/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java b/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java
index f4455ac..dc72131 100644
--- a/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java
+++ b/httpcore5-testing/src/main/java/org/apache/hc/core5/benchmark/HttpBenchmark.java
@@ -32,6 +32,7 @@ import java.net.SocketAddress;
 import java.net.URI;
 import java.nio.ByteBuffer;
 import java.nio.channels.ByteChannel;
+import java.nio.file.Paths;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -138,7 +139,7 @@ public class HttpBenchmark {
             }
             if (config.getIdentityStorePath() != null) {
                 sslContextBuilder.loadKeyMaterial(
-                        new File(config.getIdentityStorePath()),
+                        Paths.get(config.getIdentityStorePath()),
                         config.getIdentityStorePassword() != null ? config.getIdentityStorePassword().toCharArray() : null,
                         config.getIdentityStorePassword() != null ? config.getIdentityStorePassword().toCharArray() : null);
             }
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/ssl/SSLContextBuilder.java b/httpcore5/src/main/java/org/apache/hc/core5/ssl/SSLContextBuilder.java
index 886003b..97f2b4b 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/ssl/SSLContextBuilder.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/ssl/SSLContextBuilder.java
@@ -28,11 +28,13 @@
 package org.apache.hc.core5.ssl;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.Socket;
 import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
 import java.security.KeyManagementException;
 import java.security.KeyStore;
 import java.security.KeyStoreException;
@@ -95,12 +97,12 @@ public class SSLContextBuilder {
     /**
      * An empty immutable {@code KeyManager} array.
      */
-    private static final KeyManager[] EMPTY_KEY_MANAGER_ARRAY = new KeyManager[0];
+    private static final KeyManager[] EMPTY_KEY_MANAGER_ARRAY = {};
 
     /**
      * An empty immutable {@code TrustManager} array.
      */
-    private static final TrustManager[] EMPTY_TRUST_MANAGER_ARRAY = new TrustManager[0];
+    private static final TrustManager[] EMPTY_TRUST_MANAGER_ARRAY = {};
 
 
 
@@ -109,7 +111,6 @@ public class SSLContextBuilder {
     }
 
     public SSLContextBuilder() {
-        super();
         this.keyManagers = new LinkedHashSet<>();
         this.trustManagers = new LinkedHashSet<>();
     }
@@ -161,10 +162,7 @@ public class SSLContextBuilder {
      * @since 5.2
      */
     public SSLContextBuilder setTrustStoreProvider(final String name) throws NoSuchProviderException {
-        this.tsProvider = Security.getProvider(name);
-        if (this.tsProvider == null) {
-            throw new NoSuchProviderException(name);
-        }
+        this.tsProvider = requireNonNullProvider(name);
         return this;
     }
 
@@ -186,10 +184,7 @@ public class SSLContextBuilder {
      * @since 5.2
      */
     public SSLContextBuilder setKeyStoreProvider(final String name) throws NoSuchProviderException {
-        this.ksProvider = Security.getProvider(name);
-        if (this.ksProvider == null) {
-            throw new NoSuchProviderException(name);
-        }
+        this.ksProvider = requireNonNullProvider(name);
         return this;
     }
 
@@ -259,7 +254,7 @@ public class SSLContextBuilder {
     }
 
     public SSLContextBuilder loadTrustMaterial(
-            final KeyStore truststore,
+            final KeyStore trustStore,
             final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
 
         final String alg = trustManagerFactoryAlgorithm == null ?
@@ -268,15 +263,14 @@ public class SSLContextBuilder {
         final TrustManagerFactory tmFactory = tsProvider == null ?
                 TrustManagerFactory.getInstance(alg) : TrustManagerFactory.getInstance(alg, tsProvider);
 
-        tmFactory.init(truststore);
+        tmFactory.init(trustStore);
         final TrustManager[] tms = tmFactory.getTrustManagers();
         if (tms != null) {
             if (trustStrategy != null) {
                 for (int i = 0; i < tms.length; i++) {
                     final TrustManager tm = tms[i];
                     if (tm instanceof X509TrustManager) {
-                        tms[i] = new TrustManagerDelegate(
-                                (X509TrustManager) tm, trustStrategy);
+                        tms[i] = new TrustManagerDelegate((X509TrustManager) tm, trustStrategy);
                     }
                 }
             }
@@ -285,6 +279,35 @@ public class SSLContextBuilder {
         return this;
     }
 
+    /**
+     * @since 5.2
+     */
+    public SSLContextBuilder loadTrustMaterial(
+            final Path file) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
+        return loadTrustMaterial(file, null);
+    }
+
+    /**
+     * @since 5.2
+     */
+    public SSLContextBuilder loadTrustMaterial(
+            final Path file,
+            final char[] storePassword) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
+        return loadTrustMaterial(file, storePassword, null);
+    }
+
+    /**
+     * @since 5.2
+     */
+    public SSLContextBuilder loadTrustMaterial(
+            final Path file,
+            final char[] storePassword,
+            final TrustStrategy trustStrategy,
+            final OpenOption... openOptions) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
+        Args.notNull(file, "Truststore file");
+        return loadTrustMaterial(loadKeyStore(file, storePassword, openOptions), trustStrategy);
+    }
+
     public SSLContextBuilder loadTrustMaterial(
             final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException {
         return loadTrustMaterial(null, trustStrategy);
@@ -295,11 +318,7 @@ public class SSLContextBuilder {
             final char[] storePassword,
             final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
         Args.notNull(file, "Truststore file");
-        final KeyStore trustStore = KeyStore.getInstance(keyStoreType);
-        try (final FileInputStream inStream = new FileInputStream(file)) {
-            trustStore.load(inStream, storePassword);
-        }
-        return loadTrustMaterial(trustStore, trustStrategy);
+        return loadTrustMaterial(file.toPath(), storePassword, trustStrategy);
     }
 
     public SSLContextBuilder loadTrustMaterial(
@@ -318,11 +337,7 @@ public class SSLContextBuilder {
             final char[] storePassword,
             final TrustStrategy trustStrategy) throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
         Args.notNull(url, "Truststore URL");
-        final KeyStore trustStore = KeyStore.getInstance(keyStoreType);
-        try (final InputStream inStream = url.openStream()) {
-            trustStore.load(inStream, storePassword);
-        }
-        return loadTrustMaterial(trustStore, trustStrategy);
+        return loadTrustMaterial(loadKeyStore(url, storePassword), trustStrategy);
     }
 
     public SSLContextBuilder loadTrustMaterial(
@@ -332,7 +347,7 @@ public class SSLContextBuilder {
     }
 
     public SSLContextBuilder loadKeyMaterial(
-            final KeyStore keystore,
+            final KeyStore keyStore,
             final char[] keyPassword,
             final PrivateKeyStrategy aliasStrategy)
             throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
@@ -343,7 +358,7 @@ public class SSLContextBuilder {
         final KeyManagerFactory kmFactory = ksProvider == null ?
                 KeyManagerFactory.getInstance(alg) : KeyManagerFactory.getInstance(alg, ksProvider);
 
-        kmFactory.init(keystore, keyPassword);
+        kmFactory.init(keyStore, keyPassword);
         final KeyManager[] kms = kmFactory.getKeyManagers();
         if (kms != null) {
             if (aliasStrategy != null) {
@@ -359,10 +374,34 @@ public class SSLContextBuilder {
         return this;
     }
 
+    /**
+     * @since 5.2
+     */
     public SSLContextBuilder loadKeyMaterial(
-            final KeyStore keystore,
+            final Path file,
+            final char[] storePassword,
+            final char[] keyPassword,
+            final OpenOption... openOptions) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
+        return loadKeyMaterial(file, storePassword, keyPassword, null, openOptions);
+    }
+
+    /**
+     * @since 5.2
+     */
+    public SSLContextBuilder loadKeyMaterial(
+            final Path file,
+            final char[] storePassword,
+            final char[] keyPassword,
+            final PrivateKeyStrategy aliasStrategy,
+            final OpenOption... openOptions) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
+        Args.notNull(file, "Keystore file");
+        return loadKeyMaterial(loadKeyStore(file, storePassword, openOptions), keyPassword, aliasStrategy);
+    }
+
+    public SSLContextBuilder loadKeyMaterial(
+            final KeyStore keyStore,
             final char[] keyPassword) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException {
-        return loadKeyMaterial(keystore, keyPassword, null);
+        return loadKeyMaterial(keyStore, keyPassword, null);
     }
 
     public SSLContextBuilder loadKeyMaterial(
@@ -371,11 +410,7 @@ public class SSLContextBuilder {
             final char[] keyPassword,
             final PrivateKeyStrategy aliasStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
         Args.notNull(file, "Keystore file");
-        final KeyStore identityStore = KeyStore.getInstance(keyStoreType);
-        try (final FileInputStream inStream = new FileInputStream(file)) {
-            identityStore.load(inStream, storePassword);
-        }
-        return loadKeyMaterial(identityStore, keyPassword, aliasStrategy);
+        return loadKeyMaterial(file.toPath(), storePassword, keyPassword, aliasStrategy);
     }
 
     public SSLContextBuilder loadKeyMaterial(
@@ -391,11 +426,7 @@ public class SSLContextBuilder {
             final char[] keyPassword,
             final PrivateKeyStrategy aliasStrategy) throws NoSuchAlgorithmException, KeyStoreException, UnrecoverableKeyException, CertificateException, IOException {
         Args.notNull(url, "Keystore URL");
-        final KeyStore identityStore = KeyStore.getInstance(keyStoreType);
-        try (final InputStream inStream = url.openStream()) {
-            identityStore.load(inStream, storePassword);
-        }
-        return loadKeyMaterial(identityStore, keyPassword, aliasStrategy);
+        return loadKeyMaterial(loadKeyStore(url, storePassword), keyPassword, aliasStrategy);
     }
 
     public SSLContextBuilder loadKeyMaterial(
@@ -416,6 +447,24 @@ public class SSLContextBuilder {
                 secureRandom);
     }
 
+    private KeyStore loadKeyStore(final Path file, final char[] password, final OpenOption... openOptions)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
+        final KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+        try (final InputStream inputStream = Files.newInputStream(file, openOptions)) {
+            keyStore.load(inputStream, password);
+        }
+        return keyStore;
+    }
+
+    private KeyStore loadKeyStore(final URL url, final char[] password)
+            throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException {
+        final KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+        try (final InputStream inputStream = url.openStream()) {
+            keyStore.load(inputStream, password);
+        }
+        return keyStore;
+    }
+
     public SSLContext build() throws NoSuchAlgorithmException, KeyManagementException {
         final SSLContext sslContext;
         final String protocolStr = this.protocol != null ? this.protocol : TLS;
@@ -434,7 +483,6 @@ public class SSLContextBuilder {
         private final TrustStrategy trustStrategy;
 
         TrustManagerDelegate(final X509TrustManager trustManager, final TrustStrategy trustStrategy) {
-            super();
             this.trustManager = trustManager;
             this.trustStrategy = trustStrategy;
         }
@@ -466,7 +514,6 @@ public class SSLContextBuilder {
         private final PrivateKeyStrategy aliasStrategy;
 
         KeyManagerDelegate(final X509ExtendedKeyManager keyManager, final PrivateKeyStrategy aliasStrategy) {
-            super();
             this.keyManager = keyManager;
             this.aliasStrategy = aliasStrategy;
         }
@@ -481,13 +528,7 @@ public class SSLContextBuilder {
                 final String[] keyTypes, final Principal[] issuers) {
             final Map<String, PrivateKeyDetails> validAliases = new HashMap<>();
             for (final String keyType: keyTypes) {
-                final String[] aliases = this.keyManager.getClientAliases(keyType, issuers);
-                if (aliases != null) {
-                    for (final String alias: aliases) {
-                        validAliases.put(alias,
-                                new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
-                    }
-                }
+                putPrivateKeyDetails(validAliases, keyType, this.keyManager.getClientAliases(keyType, issuers));
             }
             return validAliases;
         }
@@ -495,14 +536,17 @@ public class SSLContextBuilder {
         public Map<String, PrivateKeyDetails> getServerAliasMap(
                 final String keyType, final Principal[] issuers) {
             final Map<String, PrivateKeyDetails> validAliases = new HashMap<>();
-            final String[] aliases = this.keyManager.getServerAliases(keyType, issuers);
+            putPrivateKeyDetails(validAliases, keyType, this.keyManager.getServerAliases(keyType, issuers));
+            return validAliases;
+        }
+
+        private void putPrivateKeyDetails(final Map<String, PrivateKeyDetails> validAliases, final String keyType,
+                final String[] aliases) {
             if (aliases != null) {
                 for (final String alias: aliases) {
-                    validAliases.put(alias,
-                            new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
+                    validAliases.put(alias, new PrivateKeyDetails(keyType, this.keyManager.getCertificateChain(alias)));
                 }
             }
-            return validAliases;
         }
 
         @Override
@@ -553,6 +597,14 @@ public class SSLContextBuilder {
 
     }
 
+    private Provider requireNonNullProvider(final String name) throws NoSuchProviderException {
+        final Provider provider = Security.getProvider(name);
+        if (provider == null) {
+            throw new NoSuchProviderException(name);
+        }
+        return provider;
+    }
+
     @Override
     public String toString() {
         return "[provider=" + provider + ", protocol=" + protocol + ", keyStoreType=" + keyStoreType
@@ -560,4 +612,5 @@ public class SSLContextBuilder {
                 + ", trustManagerFactoryAlgorithm=" + trustManagerFactoryAlgorithm + ", trustManagers=" + trustManagers
                 + ", secureRandom=" + secureRandom + "]";
     }
+
 }
diff --git a/pom.xml b/pom.xml
index 4435050..96de1c8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,6 +78,7 @@
     <log4j.version>2.8.2</log4j.version>
     <rxjava.version>2.2.8</rxjava.version>
     <api.comparison.version>5.1</api.comparison.version>
+    <japicmp.version>0.15.4</japicmp.version>
     <hc.animal-sniffer.signature.ignores>javax.net.ssl.SSLEngine,javax.net.ssl.SSLParameters</hc.animal-sniffer.signature.ignores>
   </properties>
 
@@ -167,7 +168,7 @@
       <plugin>
         <groupId>com.github.siom79.japicmp</groupId>
         <artifactId>japicmp-maven-plugin</artifactId>
-        <version>0.15.3</version>
+        <version>${japicmp.version}</version>
         <configuration>
           <oldVersion>
             <dependency>
@@ -298,7 +299,7 @@
       <plugin>
         <groupId>com.github.siom79.japicmp</groupId>
         <artifactId>japicmp-maven-plugin</artifactId>
-        <version>0.15.3</version>
+        <version>${japicmp.version}</version>
         <reportSets>
           <reportSet>
             <reports>