You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2019/08/08 15:04:09 UTC

[httpcomponents-core] branch master updated: Execute Socket[Channel]#connect under doPrivileged

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

olegk 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 a652854  Execute Socket[Channel]#connect under doPrivileged
a652854 is described below

commit a652854fb5e63dd8565ed199b48557043277a30d
Author: Simon Willnauer <si...@apache.org>
AuthorDate: Thu Aug 8 15:44:16 2019 +0200

    Execute Socket[Channel]#connect under doPrivileged
    
    In order to allow users to run under a security manager that only grants
    connect permission to the httpcore codebase the connect methods should
    be executed in a doPriveledged block.
    This is certainly not the only issue that users run into when they
    install a SecurityManager with strict permissions but certainly the
    most prominent and most likely one. Upstream components like the client
    might also need to protect places accessing the proxy selector etc.
---
 .../core5/http/impl/bootstrap/HttpRequester.java   | 21 +++++++++++++++++-
 .../hc/core5/reactor/SingleCoreIOReactor.java      | 25 +++++++++++++++++++++-
 2 files changed, 44 insertions(+), 2 deletions(-)

diff --git a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpRequester.java b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpRequester.java
index 492cfe8..11e3c1b 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpRequester.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/http/impl/bootstrap/HttpRequester.java
@@ -33,6 +33,9 @@ import java.io.OutputStream;
 import java.net.InetSocketAddress;
 import java.net.Proxy;
 import java.net.Socket;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
@@ -82,6 +85,7 @@ import org.apache.hc.core5.pool.ManagedConnPool;
 import org.apache.hc.core5.pool.PoolEntry;
 import org.apache.hc.core5.pool.PoolStats;
 import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.util.Asserts;
 import org.apache.hc.core5.util.TimeValue;
 import org.apache.hc.core5.util.Timeout;
 
@@ -261,7 +265,22 @@ public class HttpRequester implements ConnPoolControl<HttpHost>, ModalCloseable
         }
 
         final InetSocketAddress targetAddress = addressResolver.resolve(targetHost);
-        sock.connect(targetAddress, socketConfig.getSoTimeout().toMillisIntBound());
+        // Run this under a doPrivileged to support lib users that run under a SecurityManager this allows granting connect permissions
+        // only to this library
+        try {
+            AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+                @Override
+                public Object run() throws IOException {
+                    sock.connect(targetAddress, socketConfig.getSoTimeout().toMillisIntBound());
+                    return null;
+                }
+            });
+        } catch (final PrivilegedActionException e) {
+            Asserts.check(e.getCause() instanceof  IOException,
+                    "method contract violation only checked exceptions are wrapped: " + e.getCause());
+            // only checked exceptions are wrapped - error and RTExceptions are rethrown by doPrivileged
+            throw (IOException) e.getCause();
+        }
         if (URIScheme.HTTPS.same(targetHost.getSchemeName())) {
             final SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket(
                     sock, targetHost.getHostName(), targetAddress.getPort(), true);
diff --git a/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java b/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
index 17af207..8b92321 100644
--- a/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
+++ b/httpcore5/src/main/java/org/apache/hc/core5/reactor/SingleCoreIOReactor.java
@@ -36,6 +36,9 @@ import java.nio.channels.CancelledKeyException;
 import java.nio.channels.ClosedChannelException;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.SocketChannel;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.ConcurrentLinkedQueue;
@@ -48,6 +51,7 @@ import org.apache.hc.core5.function.Decorator;
 import org.apache.hc.core5.io.Closer;
 import org.apache.hc.core5.net.NamedEndpoint;
 import org.apache.hc.core5.util.Args;
+import org.apache.hc.core5.util.Asserts;
 import org.apache.hc.core5.util.Timeout;
 
 class SingleCoreIOReactor extends AbstractSingleCoreIOReactor implements ConnectionInitiator {
@@ -322,7 +326,26 @@ class SingleCoreIOReactor extends AbstractSingleCoreIOReactor implements Connect
             targetAddress = sessionRequest.remoteAddress;
             eventHandlerFactory = this.eventHandlerFactory;
         }
-        final boolean connected = socketChannel.connect(targetAddress);
+
+        // Run this under a doPrivileged to support lib users that run under a SecurityManager this allows granting connect permissions
+        // only to this library
+        final boolean connected;
+        try {
+            connected = AccessController.doPrivileged(
+                        new PrivilegedExceptionAction<Boolean>() {
+                            @Override
+                            public Boolean run() throws IOException {
+                                return socketChannel.connect(targetAddress);
+                            };
+                        });
+        } catch (final PrivilegedActionException e) {
+            Asserts.check(e.getCause() instanceof  IOException,
+                    "method contract violation only checked exceptions are wrapped: " + e.getCause());
+            // only checked exceptions are wrapped - error and RTExceptions are rethrown by doPrivileged
+            throw (IOException) e.getCause();
+        }
+
+
         final SelectionKey key = socketChannel.register(this.selector, SelectionKey.OP_CONNECT | SelectionKey.OP_READ);
         final InternalChannel channel = new InternalConnectChannel(key, socketChannel, sessionRequest, new InternalDataChannelFactory() {