HTTPCLIENT-1778: [OSGi] simplify handling of ManagedService based configurations

- simplify TrustedHostsConfiguration handling

git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1763263 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Julian Sedding 2016-10-04 11:29:36 +00:00
parent e9f8c5b315
commit 71d0567376
4 changed files with 53 additions and 89 deletions

View File

@ -31,13 +31,11 @@
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.sync.HttpClientBuilder; import org.apache.hc.client5.http.impl.sync.HttpClientBuilder;
import org.apache.hc.client5.http.osgi.services.ProxyConfiguration; import org.apache.hc.client5.http.osgi.services.ProxyConfiguration;
import org.apache.hc.client5.http.osgi.services.TrustedHostsConfiguration;
import org.apache.hc.client5.http.socket.ConnectionSocketFactory; import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory; import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
import org.apache.hc.core5.http.config.Registry; import org.apache.hc.core5.http.config.Registry;
import org.apache.hc.core5.http.config.RegistryBuilder; import org.apache.hc.core5.http.config.RegistryBuilder;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ManagedService;
import static org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory.getSocketFactory; import static org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory.getSocketFactory;
@ -50,12 +48,11 @@ final class HttpClientBuilderConfigurator {
private final Registry<ConnectionSocketFactory> socketFactoryRegistry; private final Registry<ConnectionSocketFactory> socketFactoryRegistry;
HttpClientBuilderConfigurator( HttpClientBuilderConfigurator(
final BundleContext bundleContext,
final List<ProxyConfiguration> proxyConfigurations, final List<ProxyConfiguration> proxyConfigurations,
final ServiceRegistration<ManagedService> trustedHostsConfiguration) { final TrustedHostsConfiguration trustedHostsConfiguration) {
credentialsProvider = new OSGiCredentialsProvider(proxyConfigurations); credentialsProvider = new OSGiCredentialsProvider(proxyConfigurations);
routePlanner = new OSGiHttpRoutePlanner(proxyConfigurations); routePlanner = new OSGiHttpRoutePlanner(proxyConfigurations);
socketFactoryRegistry = createSocketFactoryRegistry(bundleContext, trustedHostsConfiguration); socketFactoryRegistry = createSocketFactoryRegistry(trustedHostsConfiguration);
} }
<T extends HttpClientBuilder> T configure(final T clientBuilder) { <T extends HttpClientBuilder> T configure(final T clientBuilder) {
@ -67,17 +64,15 @@ <T extends HttpClientBuilder> T configure(final T clientBuilder) {
} }
private Registry<ConnectionSocketFactory> createSocketFactoryRegistry( private Registry<ConnectionSocketFactory> createSocketFactoryRegistry(
final BundleContext bundleContext, final TrustedHostsConfiguration trustedHostsConfiguration) {
final ServiceRegistration<ManagedService> trustedHostsConfiguration) {
return RegistryBuilder.<ConnectionSocketFactory>create() return RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.INSTANCE) .register("http", PlainConnectionSocketFactory.INSTANCE)
.register("https", createSocketFactory(bundleContext, trustedHostsConfiguration)) .register("https", createSocketFactory(trustedHostsConfiguration))
.build(); .build();
} }
private ConnectionSocketFactory createSocketFactory( private ConnectionSocketFactory createSocketFactory(
final BundleContext bundleContext, final TrustedHostsConfiguration trustedHostsConfiguration) {
final ServiceRegistration<ManagedService> trustedHostsConfiguration) { return new RelaxedLayeredConnectionSocketFactory(trustedHostsConfiguration, getSocketFactory());
return new RelaxedLayeredConnectionSocketFactory(bundleContext, trustedHostsConfiguration, getSocketFactory());
} }
} }

View File

@ -108,12 +108,11 @@ public void start(final BundleContext context) throws Exception {
props.put(Constants.SERVICE_PID, TRUSTED_HOSTS_PID); props.put(Constants.SERVICE_PID, TRUSTED_HOSTS_PID);
props.put(Constants.SERVICE_VENDOR, context.getBundle().getHeaders().get(Constants.BUNDLE_VENDOR)); props.put(Constants.SERVICE_VENDOR, context.getBundle().getHeaders().get(Constants.BUNDLE_VENDOR));
props.put(Constants.SERVICE_DESCRIPTION, TRUSTED_HOSTS_SERVICE_NAME); props.put(Constants.SERVICE_DESCRIPTION, TRUSTED_HOSTS_SERVICE_NAME);
trustedHostConfiguration = context.registerService(ManagedService.class, final OSGiTrustedHostsConfiguration trustedHosts = new OSGiTrustedHostsConfiguration();
new OSGiTrustedHostsConfiguration(), trustedHostConfiguration = context.registerService(ManagedService.class, trustedHosts, props);
props);
final HttpClientBuilderConfigurator configurator = final HttpClientBuilderConfigurator configurator =
new HttpClientBuilderConfigurator(context, proxyConfigurations, trustedHostConfiguration); new HttpClientBuilderConfigurator(proxyConfigurations, trustedHosts);
props.clear(); props.clear();
props.put(Constants.SERVICE_PID, BUILDER_FACTORY_SERVICE_PID); props.put(Constants.SERVICE_PID, BUILDER_FACTORY_SERVICE_PID);

View File

@ -36,23 +36,16 @@
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory; import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
import org.apache.hc.core5.http.HttpHost; import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ManagedService;
final class RelaxedLayeredConnectionSocketFactory implements LayeredConnectionSocketFactory { final class RelaxedLayeredConnectionSocketFactory implements LayeredConnectionSocketFactory {
private TrustedHostsConfiguration trustedHostsConfiguration;
private final LayeredConnectionSocketFactory defaultSocketFactory; private final LayeredConnectionSocketFactory defaultSocketFactory;
private final BundleContext bundleContext; public RelaxedLayeredConnectionSocketFactory(final TrustedHostsConfiguration trustedHostsConfiguration,
private final ServiceRegistration<ManagedService> trustedHostConfiguration;
public RelaxedLayeredConnectionSocketFactory(final BundleContext bundleContext,
final ServiceRegistration<ManagedService> trustedHostConfiguration,
final LayeredConnectionSocketFactory defaultSocketFactory) { final LayeredConnectionSocketFactory defaultSocketFactory) {
this.bundleContext = bundleContext; this.trustedHostsConfiguration = trustedHostsConfiguration;
this.trustedHostConfiguration = trustedHostConfiguration;
this.defaultSocketFactory = defaultSocketFactory; this.defaultSocketFactory = defaultSocketFactory;
} }
@ -61,26 +54,21 @@ public Socket createLayeredSocket(final Socket socket,
final String target, final String target,
final int port, final int port,
final HttpContext context) throws IOException { final HttpContext context) throws IOException {
final ManagedService trustedHostsConfigurationObject = bundleContext.getService(trustedHostConfiguration.getReference()); if (trustedHostsConfiguration.isEnabled()) {
if (trustedHostsConfigurationObject != null) { // if trust all there is no check to perform
final TrustedHostsConfiguration configuration = (TrustedHostsConfiguration) trustedHostsConfigurationObject; if (trustedHostsConfiguration.trustAll()) {
return socket;
}
if (configuration.isEnabled()) { // blindly verify the host if in the trust list
// if trust all there is no check to perform for (String trustedHost : trustedHostsConfiguration.getTrustedHosts()) {
if (configuration.trustAll()) { if (createMatcher(trustedHost).matches(target)) {
return socket; return socket;
} }
// blindly verify the host if in the trust list
for (String trustedHost : configuration.getTrustedHosts()) {
if (createMatcher(trustedHost).matches(target)) {
return socket;
}
}
} }
} }
// follow back to the default behavior // fall back to the default behavior
return defaultSocketFactory.createLayeredSocket(socket, target, port, context); return defaultSocketFactory.createLayeredSocket(socket, target, port, context);
} }

View File

@ -26,10 +26,7 @@
*/ */
package org.apache.hc.client5.http.osgi.impl; package org.apache.hc.client5.http.osgi.impl;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame; import static org.junit.Assert.assertSame;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
@ -42,79 +39,56 @@
import org.apache.hc.core5.http.protocol.BasicHttpContext; import org.apache.hc.core5.http.protocol.BasicHttpContext;
import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.protocol.HttpContext;
import org.junit.Test; import org.junit.Test;
import org.osgi.framework.BundleContext; import org.mockito.Mock;
import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
import org.osgi.service.cm.ConfigurationException; import org.osgi.service.cm.ConfigurationException;
import org.osgi.service.cm.ManagedService;
public class TestRelaxedLayeredConnectionSocketFactory { public class TestRelaxedLayeredConnectionSocketFactory {
@Mock
Socket insecureSocket;
@Mock
Socket secureSocket;
private final HttpContext context = new BasicHttpContext();
@Test @Test
public void testTrustedAllConnections() throws Exception { public void testTrustedAllConnections() throws Exception {
final HttpContext context = new BasicHttpContext(); final LayeredConnectionSocketFactory socketFactory = getLayeredConnectionSocketFactory(true, true);
final Dictionary<String, Object> config = new Hashtable<>();
config.put("trustedhosts.enabled", Boolean.TRUE);
config.put("trustedhosts.trustAll", Boolean.TRUE);
config.put("trustedhosts.hosts", new String[]{});
final LayeredConnectionSocketFactory socketFactory = getLayeredConnectionSocketFactory(config);
final Socket socket = socketFactory.createSocket(context); final Socket socket = socketFactory.createSocket(context);
final Socket secureSocket = socketFactory.createLayeredSocket(socket, "localhost", 9999, context); final Socket secureSocket = socketFactory.createLayeredSocket(socket, "localhost", 9999, context);
assertSame(socket, secureSocket); assertSame(this.secureSocket, secureSocket);
} }
@Test @Test
public void testTrustedConnections() throws Exception { public void testTrustedConnections() throws Exception {
final HttpContext context = new BasicHttpContext(); final LayeredConnectionSocketFactory socketFactory = getLayeredConnectionSocketFactory(true, false, "localhost");
final Dictionary<String, Object> config = new Hashtable<>();
config.put("trustedhosts.enabled", Boolean.TRUE);
config.put("trustedhosts.trustAll", Boolean.FALSE);
config.put("trustedhosts.hosts", new String[]{ "localhost" });
final LayeredConnectionSocketFactory socketFactory = getLayeredConnectionSocketFactory(config);
final Socket socket = socketFactory.createSocket(context); final Socket socket = socketFactory.createSocket(context);
final Socket localSecureSocket = socketFactory.createLayeredSocket(socket, "localhost", 9999, context); final Socket localSecureSocket = socketFactory.createLayeredSocket(socket, "localhost", 9999, context);
assertSame(socket, localSecureSocket); assertSame(this.insecureSocket, localSecureSocket);
final Socket apacheSecureSocket = socketFactory.createLayeredSocket(socket, "www.apache.org", 9999, context); final Socket apacheSecureSocket = socketFactory.createLayeredSocket(socket, "www.apache.org", 9999, context);
assertNotSame(socket, apacheSecureSocket); assertSame(this.secureSocket, apacheSecureSocket);
} }
@Test @Test
public void testNotEabledConfiguration() throws Exception { public void testNotEabledConfiguration() throws Exception {
final HttpContext context = new BasicHttpContext(); final LayeredConnectionSocketFactory socketFactory = getLayeredConnectionSocketFactory(false, true);
final Dictionary<String, Object> config = new Hashtable<>();
config.put("trustedhosts.enabled", Boolean.TRUE);
config.put("trustedhosts.trustAll", Boolean.FALSE);
config.put("trustedhosts.hosts", new String[]{});
final LayeredConnectionSocketFactory socketFactory = getLayeredConnectionSocketFactory(config);
final Socket socket = socketFactory.createSocket(context); final Socket socket = socketFactory.createSocket(context);
final Socket secureSocket = socketFactory.createLayeredSocket(socket, "localhost", 9999, context); final Socket secureSocket = socketFactory.createLayeredSocket(socket, "localhost", 9999, context);
assertNotSame(socket, secureSocket); assertSame(this.secureSocket, secureSocket);
} }
private LayeredConnectionSocketFactory getLayeredConnectionSocketFactory(final Dictionary<String, ?> config) { private LayeredConnectionSocketFactory getLayeredConnectionSocketFactory(
final ServiceReference<ManagedService> reference = mock(ServiceReference.class); final boolean enabled, final boolean trustAll, final String... trustedHosts) throws ConfigurationException {
final ServiceRegistration<ManagedService> registration = mock(ServiceRegistration.class);
when(registration.getReference()).thenReturn(reference);
final BundleContext bundleContext = mock(BundleContext.class);
final OSGiTrustedHostsConfiguration configuration = new OSGiTrustedHostsConfiguration(); final OSGiTrustedHostsConfiguration configuration = new OSGiTrustedHostsConfiguration();
try { configuration.updated(createConfig(enabled, trustAll, trustedHosts));
configuration.updated(config);
} catch (ConfigurationException e) {
// it doesn't happen in tests
}
when(bundleContext.getService(reference)).thenReturn(configuration);
final Socket socket = mock(Socket.class);
final Socket secureSocket = mock(Socket.class);
final LayeredConnectionSocketFactory defaultSocketFactory = new LayeredConnectionSocketFactory() { final LayeredConnectionSocketFactory defaultSocketFactory = new LayeredConnectionSocketFactory() {
@Override @Override
public Socket createSocket(final HttpContext context) throws IOException { public Socket createSocket(final HttpContext context) throws IOException {
return socket; return insecureSocket;
} }
@Override @Override
@ -125,7 +99,7 @@ public Socket connectSocket(final int connectTimeout,
final InetSocketAddress localAddress, final InetSocketAddress localAddress,
final HttpContext context ) throws IOException { final HttpContext context ) throws IOException {
// not needed in this version // not needed in this version
return socket; return insecureSocket;
} }
@Override @Override
@ -138,7 +112,15 @@ public Socket createLayeredSocket(final Socket socket,
}; };
return new RelaxedLayeredConnectionSocketFactory(bundleContext, registration, defaultSocketFactory); return new RelaxedLayeredConnectionSocketFactory(configuration, defaultSocketFactory);
}
private Dictionary<String, Object> createConfig(final boolean enabled, final boolean trustAll, final String... trustedHosts) {
final Dictionary<String, Object> config = new Hashtable<>();
config.put("trustedhosts.enabled", enabled);
config.put("trustedhosts.trustAll", trustAll);
config.put("trustedhosts.hosts", trustedHosts);
return config;
} }
} }