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/16 07:58:12 UTC

[httpcomponents-core] branch 4.4.x updated: Execute Socket[Channel]#connect under doPrivileged (#138)

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

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


The following commit(s) were added to refs/heads/4.4.x by this push:
     new 79d5ea0  Execute Socket[Channel]#connect under doPrivileged (#138)
79d5ea0 is described below

commit 79d5ea0d6633ae5a9e0d1e4409d56d290cc32ca8
Author: Simon Willnauer <si...@apache.org>
AuthorDate: Fri Aug 16 09:58:08 2019 +0200

    Execute Socket[Channel]#connect under doPrivileged (#138)
    
    * 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.
---
 .../nio/reactor/DefaultConnectingIOReactor.java    | 23 +++++++++++++++++++++-
 .../apache/http/impl/pool/BasicConnFactory.java    | 22 ++++++++++++++++++++-
 2 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/httpcore-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java b/httpcore-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java
index 1dcea63..d9118a9 100644
--- a/httpcore-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java
+++ b/httpcore-nio/src/main/java/org/apache/http/impl/nio/reactor/DefaultConnectingIOReactor.java
@@ -35,6 +35,9 @@ import java.net.UnknownHostException;
 import java.nio.channels.CancelledKeyException;
 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;
@@ -274,7 +277,25 @@ public class DefaultConnectingIOReactor extends AbstractMultiworkerIOReactor
                     sock.setReuseAddress(this.config.isSoReuseAddress());
                     sock.bind(request.getLocalAddress());
                 }
-                final boolean connected = socketChannel.connect(request.getRemoteAddress());
+
+                final SocketAddress targetAddress = request.getRemoteAddress();
+                // 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();
+                }
                 if (connected) {
                     final ChannelEntry entry = new ChannelEntry(socketChannel, request);
                     addChannel(entry);
diff --git a/httpcore/src/main/java/org/apache/http/impl/pool/BasicConnFactory.java b/httpcore/src/main/java/org/apache/http/impl/pool/BasicConnFactory.java
index 508fa52..4c11082 100644
--- a/httpcore/src/main/java/org/apache/http/impl/pool/BasicConnFactory.java
+++ b/httpcore/src/main/java/org/apache/http/impl/pool/BasicConnFactory.java
@@ -29,6 +29,9 @@ package org.apache.http.impl.pool;
 import java.io.IOException;
 import java.net.InetSocketAddress;
 import java.net.Socket;
+import java.security.AccessController;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
 
 import javax.net.SocketFactory;
 import javax.net.ssl.SSLSocketFactory;
@@ -47,6 +50,7 @@ import org.apache.http.params.HttpParamConfig;
 import org.apache.http.params.HttpParams;
 import org.apache.http.pool.ConnFactory;
 import org.apache.http.util.Args;
+import org.apache.http.util.Asserts;
 
 /**
  * A very basic {@link ConnFactory} implementation that creates
@@ -177,7 +181,23 @@ public class BasicConnFactory implements ConnFactory<HttpHost, HttpClientConnect
             socket.setSoLinger(true, linger);
         }
         socket.setKeepAlive(this.sconfig.isSoKeepAlive());
-        socket.connect(new InetSocketAddress(hostname, port), this.connectTimeout);
+        // Run this under a doPrivileged to support lib users that run under a SecurityManager this allows granting connect permissions
+        // only to this library
+        final InetSocketAddress address = new InetSocketAddress(hostname, port);
+        try {
+            AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+                @Override
+                public Object run() throws IOException {
+                    socket.connect(address, BasicConnFactory.this.connectTimeout);
+                    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();
+        }
         return this.connFactory.createConnection(socket);
     }