Skip to content

Commit

Permalink
Support for proxy in HttpUrlConnector
Browse files Browse the repository at this point in the history
Signed-off-by: Jorge Bescos Gascon <jorge.bescos.gascon@oracle.com>
  • Loading branch information
jbescos committed Jun 22, 2022
1 parent e114d5e commit f850e5e
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.Proxy;
import java.net.URL;
import java.util.Map;
import java.util.logging.Logger;
Expand Down Expand Up @@ -263,17 +264,18 @@ public interface ConnectionFactory {
* </p>
*
* @param url the endpoint URL.
* @param proxy the configured proxy or null.
* @return the {@link java.net.HttpURLConnection}.
* @throws java.io.IOException in case the connection cannot be provided.
*/
public HttpURLConnection getConnection(URL url) throws IOException;
public HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException;
}

private static class DefaultConnectionFactory implements ConnectionFactory {

@Override
public HttpURLConnection getConnection(final URL url) throws IOException {
return (HttpURLConnection) url.openConnection();
public HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException {
return (HttpURLConnection) (proxy != null ? url.openConnection(proxy) : url.openConnection());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2022 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand All @@ -21,13 +21,18 @@
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
Expand All @@ -39,15 +44,15 @@
import java.util.logging.Logger;
import java.util.stream.Collectors;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;

import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.ClientRequest;
import org.glassfish.jersey.client.ClientResponse;
Expand Down Expand Up @@ -314,10 +319,54 @@ protected void secureConnection(final JerseyClient client, final HttpURLConnecti
}
}

private URI getProxyUri(Object proxy) {
if (proxy instanceof URI) {
return (URI) proxy;
} else if (proxy instanceof String) {
return URI.create((String) proxy);
} else {
throw new ProcessingException(LocalizationMessages.WRONG_PROXY_URI_TYPE(ClientProperties.PROXY_URI));
}
}

private String getFromConfigOrSystem(ClientRequest request, String clientProperty, String systemProperty) {
String result = request.resolveProperty(clientProperty, String.class);
if (result == null) {
result = System.getProperty(systemProperty);
}
return result;
}

private URI getProxyUri(ClientRequest request) {
Configuration config = request.getConfiguration();
Object proxyUri = config.getProperty(ClientProperties.PROXY_URI);
if (proxyUri == null) {
String proxyHost = System.getProperty("http.proxyHost");
String proxyPort = System.getProperty("http.proxyPort");
if (proxyHost != null && proxyPort != null) {
return URI.create(proxyHost + ":" + proxyPort);
}
} else {
return getProxyUri(proxyUri);
}
return null;
}

private ClientResponse _apply(final ClientRequest request) throws IOException {
final HttpURLConnection uc;

uc = this.connectionFactory.getConnection(request.getUri().toURL());
Proxy proxy = null;
URI proxyUri = getProxyUri(request);
if (proxyUri != null) {
String username = getFromConfigOrSystem(request, ClientProperties.PROXY_USERNAME, "http.proxyUser");
String password = getFromConfigOrSystem(request, ClientProperties.PROXY_PASSWORD, "http.proxyPassword");
if (username != null && password != null) {
StringBuilder auth = new StringBuilder().append(username).append(":").append(password);
String encoded = "Basic " + Base64.getEncoder().encodeToString(auth.toString().getBytes());
request.getHeaders().put("Proxy-Authorization", Arrays.asList(encoded));
}
proxy = new Proxy(Type.HTTP, new InetSocketAddress(proxyUri.getHost(), proxyUri.getPort()));
}
uc = this.connectionFactory.getConnection(request.getUri().toURL(), proxy);
uc.setDoInput(true);

final String httpMethod = request.getMethod();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012, 2022 Oracle and/or its affiliates. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -84,3 +84,4 @@ error.request.cancelled=Request cancelled by the client call.
error.listener.init=ClientLifecycleListener {0} failed to initialize properly.
error.listener.close=ClientLifecycleListener {0} failed to close properly.
error.shutdownhook.close=Client shutdown hook {0} failed.
wrong.proxy.uri.type=The proxy URI ("{0}") property MUST be an instance of String or URI.
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@

package org.glassfish.jersey.client;

import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.ProtocolException;
import java.net.Proxy;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URL;
Expand All @@ -30,6 +33,10 @@
import java.util.List;
import java.util.Map;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocketFactory;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
Expand All @@ -39,17 +46,10 @@
import javax.ws.rs.core.Link;
import javax.ws.rs.core.Response;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLPeerUnverifiedException;
import javax.net.ssl.SSLSocketFactory;

import org.glassfish.jersey.client.internal.HttpUrlConnector;

import org.junit.Assert;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.assertEquals;

/**
* Various tests for the default client connector.
Expand Down Expand Up @@ -91,7 +91,7 @@ public void testConnectionTimeoutNoEntity() {
public void testResolvedRequestUri() {
HttpUrlConnectorProvider.ConnectionFactory factory = new HttpUrlConnectorProvider.ConnectionFactory() {
@Override
public HttpURLConnection getConnection(URL endpointUrl) throws IOException {
public HttpURLConnection getConnection(URL endpointUrl, Proxy proxy) throws IOException {
HttpURLConnection result = (HttpURLConnection) endpointUrl.openConnection();
return wrapRedirectedHttp(result);
}
Expand Down Expand Up @@ -435,7 +435,7 @@ public void testSSLConnection() {
ClientRequest request = client.target("https://localhost:8080").request().buildGet().request();
HttpUrlConnectorProvider.ConnectionFactory factory = new HttpUrlConnectorProvider.ConnectionFactory() {
@Override
public HttpURLConnection getConnection(URL endpointUrl) throws IOException {
public HttpURLConnection getConnection(URL endpointUrl, Proxy proxy) throws IOException {
HttpURLConnection result = (HttpURLConnection) endpointUrl.openConnection();
return wrapNoContentHttps(result);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.client.spi.ConnectorProvider;
import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
Expand All @@ -44,6 +46,7 @@
import javax.ws.rs.core.Response;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
Expand All @@ -57,6 +60,8 @@
@RunWith(Parameterized.class)
public class ProxySelectorTest {
private static final String NO_PASS = "no-pass";
private static final String PROXY_USERNAME = "proxy-user";
private static final String PROXY_PASSWORD = "proxy-password";

@Parameterized.Parameters(name = "{index}: {0}")
public static List<Object[]> testData() {
Expand All @@ -65,6 +70,7 @@ public static List<Object[]> testData() {
// {Apache5ConnectorProvider.class},
// {JettyConnectorProvider.class},
{NettyConnectorProvider.class},
{HttpUrlConnectorProvider.class},
});
}

Expand Down Expand Up @@ -95,6 +101,23 @@ public void testGet407() {
}
}

@Test
public void testGetSuccess() {
// Next applies for HttpUrlConnectorProvider. It seems Netty is not supporting user/pass in System properties
if (connectorProvider.getClass() == HttpUrlConnectorProvider.class) {
try {
System.setProperty("http.proxyUser", PROXY_USERNAME);
System.setProperty("http.proxyPassword", PROXY_PASSWORD);
Response response = target("proxyTest").request().get();
response.bufferEntity();
assertEquals(response.readEntity(String.class), 200, response.getStatus());
} finally {
System.clearProperty("http.proxyUser");
System.clearProperty("http.proxyPassword");
}
}
}

private static Server server;
@BeforeClass
public static void startFakeProxy() {
Expand Down Expand Up @@ -148,6 +171,29 @@ public void handle(String target,
HttpServletResponse response) {
if (request.getHeader(NO_PASS) != null) {
response.setStatus(Integer.parseInt(request.getHeader(NO_PASS)));
} else if (request.getHeader("Proxy-Authorization") != null) {
String proxyAuthorization = request.getHeader("Proxy-Authorization");
String decoded = new String(Base64.getDecoder().decode(proxyAuthorization.substring(6).getBytes()));
final String[] split = decoded.split(":");
final String username = split[0];
final String password = split[1];

if (!username.equals(PROXY_USERNAME)) {
response.setStatus(400);
System.out.println("Found unexpected username: " + username);
}

if (!password.equals(PROXY_PASSWORD)) {
response.setStatus(400);
System.out.println("Found unexpected password: " + username);
}

if (response.getStatus() != 400) {
response.setStatus(200);
if ("CONNECT".equalsIgnoreCase(baseRequest.getMethod())) { // NETTY way of doing proxy
httpConnect.add(baseRequest.getHttpChannel());
}
}
} else {
response.setStatus(407);
response.addHeader("Proxy-Authenticate", "Basic");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.ClientProperties;
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.client.spi.ConnectorProvider;
import org.glassfish.jersey.jetty.connector.JettyConnectorProvider;
import org.glassfish.jersey.netty.connector.NettyConnectorProvider;
Expand Down Expand Up @@ -72,6 +73,7 @@ public static List<Object[]> testData() {
{Apache5ConnectorProvider.class},
{JettyConnectorProvider.class},
{NettyConnectorProvider.class},
{HttpUrlConnectorProvider.class},
});
}

Expand Down Expand Up @@ -110,7 +112,8 @@ public void testGetSuccess() {
client().property(ClientProperties.PROXY_USERNAME, ProxyTest.PROXY_USERNAME);
client().property(ClientProperties.PROXY_PASSWORD, ProxyTest.PROXY_PASSWORD);
Response response = target("proxyTest").request().get();
assertEquals(200, response.getStatus());
response.bufferEntity();
assertEquals(response.readEntity(String.class), 200, response.getStatus());
}

private static Server server;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@

package org.glassfish.jersey.tests.e2e.client.connector.ssl;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.Proxy;
import java.net.Socket;
import java.net.URL;
import java.util.List;
Expand All @@ -30,24 +34,20 @@
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.Response;

import org.glassfish.jersey.apache.connector.ApacheConnectorProvider;
import org.glassfish.jersey.apache5.connector.Apache5ConnectorProvider;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.client.HttpUrlConnectorProvider;
import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature;
import org.glassfish.jersey.logging.LoggingFeature;

import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

/**
* Test custom socket factory in HttpUrlConnection using SSL
Expand All @@ -70,7 +70,7 @@ public void testSSLWithCustomSocketFactory() throws Exception {
.connectorProvider(new HttpUrlConnectorProvider().connectionFactory(
new HttpUrlConnectorProvider.ConnectionFactory() {
@Override
public HttpURLConnection getConnection(final URL url) throws IOException {
public HttpURLConnection getConnection(URL url, Proxy proxy) throws IOException {
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setSSLSocketFactory(socketFactory);
return connection;
Expand Down

0 comments on commit f850e5e

Please sign in to comment.