Index: src/main/java/org/apache/hc/client5/http/osgi/impl/HostMatcher.java =================================================================== --- src/main/java/org/apache/hc/client5/http/osgi/impl/HostMatcher.java (revision 0) +++ src/main/java/org/apache/hc/client5/http/osgi/impl/HostMatcher.java (working copy) @@ -0,0 +1,158 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.hc.client5.http.osgi.impl; + +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +interface HostMatcher { + + public static final String DOT = "."; + + /** + * The IP mask pattern against which hosts are matched. + */ + public static final Pattern IP_MASK_PATTERN = Pattern.compile("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + + "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"); + + boolean matches(String host); + + public static class HostMatcherFactory { + + public static HostMatcher createMatcher(final String name) { + final NetworkAddress na = NetworkAddress.parse(name); + if (na != null) { + return new IPAddressMatcher(na); + } + + if (name.startsWith(DOT)) { + return new DomainNameMatcher(name); + } + + return new HostNameMatcher(name); + } + + } + + public static class HostNameMatcher implements HostMatcher { + + private final String hostName; + + HostNameMatcher(final String hostName) { + this.hostName = hostName; + } + + @Override + public boolean matches(final String host) { + return hostName.equalsIgnoreCase(host); + } + } + + public static class DomainNameMatcher implements HostMatcher { + + private final String domainName; + + DomainNameMatcher(final String domainName) { + this.domainName = domainName.toLowerCase(Locale.ROOT); + } + + @Override + public boolean matches(final String host) { + return host.toLowerCase(Locale.ROOT).endsWith(domainName); + } + } + + public static class IPAddressMatcher implements HostMatcher { + + private final NetworkAddress address; + + IPAddressMatcher(final NetworkAddress address) { + this.address = address; + } + + @Override + public boolean matches(final String host) { + final NetworkAddress hostAddress = NetworkAddress.parse(host); + return hostAddress != null && address.address == (hostAddress.address & address.mask); + } + + } + + public static class NetworkAddress { + + final int address; + + final int mask; + + static NetworkAddress parse(final String adrSpec) { + + if (null != adrSpec) { + final Matcher nameMatcher = IP_MASK_PATTERN.matcher(adrSpec); + if (nameMatcher.matches()) { + try { + final int i1 = toInt(nameMatcher.group(1), 255); + final int i2 = toInt(nameMatcher.group(2), 255); + final int i3 = toInt(nameMatcher.group(3), 255); + final int i4 = toInt(nameMatcher.group(4), 255); + final int ip = i1 << 24 | i2 << 16 | i3 << 8 | i4; + + int mask = toInt(nameMatcher.group(4), 32); + mask = (mask == 32) ? -1 : -1 - (-1 >>> mask); + + return new NetworkAddress(ip, mask); + } catch (final NumberFormatException nfe) { + // not expected after the pattern match ! + } + } + } + + return null; + } + + private static int toInt(final String value, final int max) { + if (value == null || value.isEmpty()) { + return max; + } + + int number = Integer.parseInt(value); + if (number > max) { + number = max; + } + return number; + } + + NetworkAddress(final int address, final int mask) { + this.address = address; + this.mask = mask; + } + + } + +} Property changes on: src/main/java/org/apache/hc/client5/http/osgi/impl/HostMatcher.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Date Author Id Revision HeadURL \ No newline at end of property Index: src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiHttpRoutePlanner.java =================================================================== --- src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiHttpRoutePlanner.java (revision 1753485) +++ src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiHttpRoutePlanner.java (working copy) @@ -26,10 +26,9 @@ */ package org.apache.hc.client5.http.osgi.impl; -import java.util.Locale; +import static org.apache.hc.client5.http.osgi.impl.HostMatcher.HostMatcherFactory.createMatcher; + import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner; import org.apache.hc.client5.http.osgi.services.ProxyConfiguration; @@ -45,16 +44,6 @@ */ final class OSGiHttpRoutePlanner extends DefaultRoutePlanner { - private static final String DOT = "."; - - /** - * The IP mask pattern against which hosts are matched. - */ - public static final Pattern IP_MASK_PATTERN = Pattern.compile("^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + - "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + - "([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\." + - "([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"); - private final BundleContext bundleContext; private final Map registeredConfigurations; @@ -95,117 +84,4 @@ return proxyHost; } - private static HostMatcher createMatcher(final String name) { - final NetworkAddress na = NetworkAddress.parse(name); - if (na != null) { - return new IPAddressMatcher(na); - } - - if (name.startsWith(DOT)) { - return new DomainNameMatcher(name); - } - - return new HostNameMatcher(name); - } - - private interface HostMatcher { - - boolean matches(String host); - - } - - private static class HostNameMatcher implements HostMatcher { - - private final String hostName; - - HostNameMatcher(final String hostName) { - this.hostName = hostName; - } - - @Override - public boolean matches(final String host) { - return hostName.equalsIgnoreCase(host); - } - } - - private static class DomainNameMatcher implements HostMatcher { - - private final String domainName; - - DomainNameMatcher(final String domainName) { - this.domainName = domainName.toLowerCase(Locale.ROOT); - } - - @Override - public boolean matches(final String host) { - return host.toLowerCase(Locale.ROOT).endsWith(domainName); - } - } - - private static class IPAddressMatcher implements HostMatcher { - - private final NetworkAddress address; - - IPAddressMatcher(final NetworkAddress address) { - this.address = address; - } - - @Override - public boolean matches(final String host) { - final NetworkAddress hostAddress = NetworkAddress.parse(host); - return hostAddress != null && address.address == (hostAddress.address & address.mask); - } - - } - - private static class NetworkAddress { - - final int address; - - final int mask; - - static NetworkAddress parse(final String adrSpec) { - - if (null != adrSpec) { - final Matcher nameMatcher = IP_MASK_PATTERN.matcher(adrSpec); - if (nameMatcher.matches()) { - try { - final int i1 = toInt(nameMatcher.group(1), 255); - final int i2 = toInt(nameMatcher.group(2), 255); - final int i3 = toInt(nameMatcher.group(3), 255); - final int i4 = toInt(nameMatcher.group(4), 255); - final int ip = i1 << 24 | i2 << 16 | i3 << 8 | i4; - - int mask = toInt(nameMatcher.group(4), 32); - mask = (mask == 32) ? -1 : -1 - (-1 >>> mask); - - return new NetworkAddress(ip, mask); - } catch (final NumberFormatException nfe) { - // not expected after the pattern match ! - } - } - } - - return null; - } - - private static int toInt(final String value, final int max) { - if (value == null || value.isEmpty()) { - return max; - } - - int number = Integer.parseInt(value); - if (number > max) { - number = max; - } - return number; - } - - NetworkAddress(final int address, final int mask) { - this.address = address; - this.mask = mask; - } - - } - } Index: src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiTrustedHostsConfiguration.java =================================================================== --- src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiTrustedHostsConfiguration.java (revision 0) +++ src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiTrustedHostsConfiguration.java (working copy) @@ -0,0 +1,81 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.hc.client5.http.osgi.impl; + +import static java.lang.String.format; +import static java.util.Arrays.asList; +import static org.apache.hc.client5.http.osgi.impl.PropertiesUtils.to; + +import java.util.Dictionary; + +import org.apache.hc.client5.http.osgi.services.TrustedHostsConfiguration; + +/** + * @since 5.0-alpha2 + */ +final class OSGiTrustedHostsConfiguration implements TrustedHostsConfiguration { + + /** + * Property indicating whether this particular configuration . Defaults to false. + */ + private static final String PROPERTYNAME_TRUST_ALL = "trustedHosts.trustAll"; + + private static final Boolean PROPERTYDEFAULT_TRUST_ALL = Boolean.FALSE; + + /** + * A multivalue property representing host patterns which is an acceptable match with the server's authentication scheme. + * By default localhost (127.0.0.1) is trusted. + */ + private static final String PROPERTYNAME_TRUSTED_HOSTS = "trustedHosts.hosts"; + + private static final String[] PROPERTYDEFAULT_TRUSTED_HOSTS = new String[]{ "localhost", "127.0.0.1" }; + + private Boolean trustAll = Boolean.FALSE; // fewer boxing conversions needed when stored as an object + + private String[] trustedHosts; + + @Override + public boolean trustAll() { + return trustAll; + } + + @Override + public String[] getTrustedHosts() { + return trustedHosts; + } + + public void update(final Dictionary config) { + trustAll = to(config.get(PROPERTYNAME_TRUST_ALL), boolean.class, PROPERTYDEFAULT_TRUST_ALL); + trustedHosts = to(config.get(PROPERTYNAME_TRUSTED_HOSTS), String[].class, PROPERTYDEFAULT_TRUSTED_HOSTS); + } + + @Override + public String toString() { + return format("ProxyConfiguration [trustAll=%s, trustedHosts=%s]", trustAll, asList(trustedHosts)); + } + +} Property changes on: src/main/java/org/apache/hc/client5/http/osgi/impl/OSGiTrustedHostsConfiguration.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Date Author Id Revision HeadURL \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: src/main/java/org/apache/hc/client5/http/osgi/impl/RelaxedLayeredConnectionSocketFactory.java =================================================================== --- src/main/java/org/apache/hc/client5/http/osgi/impl/RelaxedLayeredConnectionSocketFactory.java (revision 0) +++ src/main/java/org/apache/hc/client5/http/osgi/impl/RelaxedLayeredConnectionSocketFactory.java (working copy) @@ -0,0 +1,88 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.hc.client5.http.osgi.impl; + +import static org.apache.hc.client5.http.osgi.impl.HostMatcher.HostMatcherFactory.createMatcher; +import static org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory.getSocketFactory; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; + +import org.apache.hc.client5.http.osgi.services.TrustedHostsConfiguration; +import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.protocol.HttpContext; + +final class RelaxedLayeredConnectionSocketFactory implements LayeredConnectionSocketFactory { + + private final SSLConnectionSocketFactory defaultSocketFactory = getSocketFactory(); + + private final TrustedHostsConfiguration configuration; + + public RelaxedLayeredConnectionSocketFactory(final TrustedHostsConfiguration configuration) { + this.configuration = configuration; + } + + @Override + public Socket createLayeredSocket(final Socket socket, + final String target, + final int port, + final HttpContext context) throws IOException { + // if trust all there is no check to perform + if (configuration.trustAll()) { + 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 behaviour + return defaultSocketFactory.createLayeredSocket(socket, target, port, context); + } + + @Override + public Socket createSocket(final HttpContext context) throws IOException { + return defaultSocketFactory.createSocket(context); + } + + @Override + public Socket connectSocket(final int connectTimeout, + final Socket sock, + final HttpHost host, + final InetSocketAddress remoteAddress, + final InetSocketAddress localAddress, + final HttpContext context) throws IOException { + return defaultSocketFactory.connectSocket(connectTimeout, sock, host, remoteAddress, localAddress, context); + } + +} Property changes on: src/main/java/org/apache/hc/client5/http/osgi/impl/RelaxedLayeredConnectionSocketFactory.java ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Date Author Id Revision HeadURL \ No newline at end of property Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: src/main/java/org/apache/hc/client5/http/osgi/services/TrustedHostsConfiguration.java =================================================================== --- src/main/java/org/apache/hc/client5/http/osgi/services/TrustedHostsConfiguration.java (revision 0) +++ src/main/java/org/apache/hc/client5/http/osgi/services/TrustedHostsConfiguration.java (working copy) @@ -0,0 +1,43 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.hc.client5.http.osgi.services; + +/** + * @since 5.0-alpha2 + */ +public interface TrustedHostsConfiguration { + + /** + * Pay attention on no enabling this feature in production environment as it is totally insecure. + * + * @return + */ + boolean trustAll(); + + String[] getTrustedHosts(); + +} Property changes on: src/main/java/org/apache/hc/client5/http/osgi/services/TrustedHostsConfiguration.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Date Author Id Revision HeadURL \ No newline at end of property