From 902a79b8ee0e07983289a75ca2c71349ec2e622b Mon Sep 17 00:00:00 2001 From: Kai Rasmussen Date: Thu, 30 Jun 2016 14:08:58 -0400 Subject: [PATCH 1/2] Respect property https.protocols API's are disabling TLS v1 in favor of the more secure protocols TLS 1.1 or TLS 1.2. Java has a system property for setting this, https.protocols, that this library completely ignores. Updating the library so that this property is used to set the transport protocols. Upgrading http-client version to 4.5.2 for the SSLConnectionSocketFactory builder Fixing testRedirect() - google redirects http - https now Fixes issue https://github.com/jgritman/httpbuilder/issues/56 --- pom.xml | 2 +- .../java/groovyx/net/http/HTTPBuilder.java | 65 ++++++++++--------- .../http/thirdparty/GAEClientConnection.java | 20 +++++- .../groovyx/net/http/HttpURLClientTest.groovy | 2 +- 4 files changed, 56 insertions(+), 33 deletions(-) mode change 100644 => 100755 pom.xml mode change 100644 => 100755 src/main/java/groovyx/net/http/HTTPBuilder.java mode change 100644 => 100755 src/main/java/groovyx/net/http/thirdparty/GAEClientConnection.java mode change 100644 => 100755 src/test/groovy/groovyx/net/http/HttpURLClientTest.groovy diff --git a/pom.xml b/pom.xml old mode 100644 new mode 100755 index e67fa4e..bdbd5c5 --- a/pom.xml +++ b/pom.xml @@ -27,7 +27,7 @@ org.apache.httpcomponents httpclient - 4.2.1 + 4.5.2 diff --git a/src/main/java/groovyx/net/http/HTTPBuilder.java b/src/main/java/groovyx/net/http/HTTPBuilder.java old mode 100644 new mode 100755 index 0f9ec9e..c51a112 --- a/src/main/java/groovyx/net/http/HTTPBuilder.java +++ b/src/main/java/groovyx/net/http/HTTPBuilder.java @@ -21,37 +21,14 @@ */ package groovyx.net.http; -import static groovyx.net.http.URIBuilder.convertToURI; +import com.google.appengine.repackaged.com.google.common.base.StringUtil; import groovy.lang.Closure; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Map; - +import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpEntityEnclosingRequest; -import org.apache.http.HttpHost; -import org.apache.http.HttpResponse; +import org.apache.http.*; import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; @@ -60,18 +37,37 @@ import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.params.ConnRoutePNames; import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.cookie.params.CookieSpecPNames; -import org.apache.http.client.HttpClient; import org.apache.http.impl.client.AbstractHttpClient; import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.impl.client.HttpClients; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HttpContext; +import org.apache.http.ssl.SSLContexts; import org.codehaus.groovy.runtime.DefaultGroovyMethods; import org.codehaus.groovy.runtime.MethodClosure; +import javax.net.ssl.SSLContext; +import java.io.*; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Map; + +import static groovyx.net.http.URIBuilder.convertToURI; + /**

* Groovy DSL for easily making HTTP requests, and handling request and response * data. This class adds a number of convenience mechanisms built on top of @@ -855,7 +851,18 @@ public void setClient(HttpClient client) { * @return */ protected HttpClient createClient( HttpParams params ) { - return new DefaultHttpClient(params); + String protocols = System.getProperty("https.protocols"); + if(StringUtils.isNotBlank(protocols)) { + String[] protocolArray = protocols.split(","); + SSLContext sslContext = SSLContexts.createDefault(); + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, + protocolArray, + null, + new NoopHostnameVerifier()); + return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + } else { + return new DefaultHttpClient(params); + } } /** diff --git a/src/main/java/groovyx/net/http/thirdparty/GAEClientConnection.java b/src/main/java/groovyx/net/http/thirdparty/GAEClientConnection.java old mode 100644 new mode 100755 index d46dc7a..9ba4dda --- a/src/main/java/groovyx/net/http/thirdparty/GAEClientConnection.java +++ b/src/main/java/groovyx/net/http/thirdparty/GAEClientConnection.java @@ -23,6 +23,7 @@ of the License, or (at your option) any later version. import java.io.*; import java.net.*; +import java.util.UUID; import java.util.concurrent.TimeUnit; import org.apache.http.*; import org.apache.http.conn.*; @@ -34,14 +35,16 @@ of the License, or (at your option) any later version. import com.google.appengine.api.urlfetch.*; -class GAEClientConnection - implements ManagedClientConnection { +class GAEClientConnection implements ManagedClientConnection { + + final String id; public GAEClientConnection(ClientConnectionManager cm, HttpRoute route, Object state) { this.connManager = cm; this.route = route; this.state = state; this.closed = true; + id = UUID.randomUUID().toString(); } // From interface ManagedClientConnection @@ -281,6 +284,19 @@ public void abortConnection() private HTTPRequest request; private HTTPResponse response; private boolean closed; + private Socket socket; private static URLFetchService urlFS = URLFetchServiceFactory.getURLFetchService(); + + public String getId() { + return id; + } + + public void bind(Socket socket) throws IOException { + this.socket = socket; + } + + public Socket getSocket() { + return socket; + } } diff --git a/src/test/groovy/groovyx/net/http/HttpURLClientTest.groovy b/src/test/groovy/groovyx/net/http/HttpURLClientTest.groovy old mode 100644 new mode 100755 index 43ee8da..000210e --- a/src/test/groovy/groovyx/net/http/HttpURLClientTest.groovy +++ b/src/test/groovy/groovyx/net/http/HttpURLClientTest.groovy @@ -36,7 +36,7 @@ class HttpURLClientTest { @Test public void testRedirect() { def http = new HttpURLClient(followRedirects:false) - def params = [ url:'http://www.google.com/search', + def params = [ url:'https://www.google.com/search', query:[q:'HTTPBuilder', btnI:"I'm Feeling Lucky"], headers:['User-Agent':'Firefox'] ] def resp = http.request( params ) From 26e02e4051fa721ff1fdae4de4acc5a6e3cf6725 Mon Sep 17 00:00:00 2001 From: Kai Rasmussen Date: Wed, 13 Jul 2016 14:51:44 -0400 Subject: [PATCH 2/2] Fix basic auth when using the HttpBuilder --- .../java/groovyx/net/http/AuthConfig.java | 50 ++++++++-------- .../java/groovyx/net/http/HTTPBuilder.java | 57 ++++++++++++------- 2 files changed, 60 insertions(+), 47 deletions(-) mode change 100644 => 100755 src/main/java/groovyx/net/http/AuthConfig.java diff --git a/src/main/java/groovyx/net/http/AuthConfig.java b/src/main/java/groovyx/net/http/AuthConfig.java old mode 100644 new mode 100755 index e62204a..4094bc8 --- a/src/main/java/groovyx/net/http/AuthConfig.java +++ b/src/main/java/groovyx/net/http/AuthConfig.java @@ -21,26 +21,10 @@ */ package groovyx.net.http; -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; -import java.security.GeneralSecurityException; -import java.security.KeyStore; -import java.util.HashMap; -import java.util.Map; - import oauth.signpost.OAuthConsumer; import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer; import oauth.signpost.exception.OAuthException; - -import org.apache.http.Header; -import org.apache.http.HttpEntityEnclosingRequest; -import org.apache.http.HttpException; -import org.apache.http.HttpHost; -import org.apache.http.HttpRequest; -import org.apache.http.HttpRequestInterceptor; +import org.apache.http.*; import org.apache.http.auth.AuthScope; import org.apache.http.auth.NTCredentials; import org.apache.http.auth.UsernamePasswordCredentials; @@ -48,9 +32,20 @@ import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.AbstractHttpClient; +import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.protocol.ExecutionContext; import org.apache.http.protocol.HttpContext; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.util.HashMap; +import java.util.Map; + /** * Encapsulates all configuration related to HTTP authentication methods. * @see HTTPBuilder#getAuth() @@ -85,14 +80,19 @@ public void basic( String user, String pass ) { * @param pass */ public void basic( String host, int port, String user, String pass ) { - final HttpClient client = builder.getClient(); - if ( !(client instanceof AbstractHttpClient )) { - throw new IllegalStateException("client is not an AbstractHttpClient"); - } - ((AbstractHttpClient)client).getCredentialsProvider().setCredentials( - new AuthScope( host, port ), - new UsernamePasswordCredentials( user, pass ) - ); + AuthScope authScope = new AuthScope(host, port); + UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(user, pass); + final HttpClient client = builder.getClient(); + if (client instanceof AbstractHttpClient) { + ((AbstractHttpClient)client).getCredentialsProvider().setCredentials( + authScope, + credentials + ); + } else if(client instanceof CloseableHttpClient){ + builder.setCredentials(authScope, credentials); + } else { + throw new IllegalStateException("client is not an AbstractHttpClient"); + } } /** diff --git a/src/main/java/groovyx/net/http/HTTPBuilder.java b/src/main/java/groovyx/net/http/HTTPBuilder.java index c51a112..8237480 100755 --- a/src/main/java/groovyx/net/http/HTTPBuilder.java +++ b/src/main/java/groovyx/net/http/HTTPBuilder.java @@ -21,13 +21,15 @@ */ package groovyx.net.http; -import com.google.appengine.repackaged.com.google.common.base.StringUtil; import groovy.lang.Closure; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.*; +import org.apache.http.auth.AuthScope; +import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.CredentialsProvider; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; @@ -42,9 +44,7 @@ import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.conn.ssl.TrustStrategy; import org.apache.http.cookie.params.CookieSpecPNames; -import org.apache.http.impl.client.AbstractHttpClient; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.client.HttpClients; +import org.apache.http.impl.client.*; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HttpContext; @@ -171,7 +171,7 @@ */ public class HTTPBuilder { - private HttpClient client; + private HttpClient client; protected URIBuilder defaultURI = null; protected AuthConfig auth = new AuthConfig( this ); @@ -188,8 +188,14 @@ public class HTTPBuilder { protected EncoderRegistry encoders = new EncoderRegistry(); protected ParserRegistry parsers = new ParserRegistry(); + public static final HttpParams DEFAULT_PARAMS = new BasicHttpParams(); - /** + static{ + DEFAULT_PARAMS.setParameter( CookieSpecPNames.DATE_PATTERNS, + Arrays.asList("EEE, dd-MMM-yyyy HH:mm:ss z", "EEE, dd MMM yyyy HH:mm:ss z") ); + } + + /** * Creates a new instance with a null default URI. */ public HTTPBuilder() { @@ -832,10 +838,7 @@ public Map getHeaders() { */ public HttpClient getClient() { if (client == null) { - HttpParams defaultParams = new BasicHttpParams(); - defaultParams.setParameter( CookieSpecPNames.DATE_PATTERNS, - Arrays.asList("EEE, dd-MMM-yyyy HH:mm:ss z", "EEE, dd MMM yyyy HH:mm:ss z") ); - client = createClient(defaultParams); + client = createClient(DEFAULT_PARAMS); } return client; } @@ -850,22 +853,27 @@ public void setClient(HttpClient client) { * @param params * @return */ - protected HttpClient createClient( HttpParams params ) { - String protocols = System.getProperty("https.protocols"); - if(StringUtils.isNotBlank(protocols)) { - String[] protocolArray = protocols.split(","); - SSLContext sslContext = SSLContexts.createDefault(); - SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, - protocolArray, - null, - new NoopHostnameVerifier()); - return HttpClients.custom().setSSLSocketFactory(sslsf).build(); + protected HttpClient createClient( HttpParams params) { + if(StringUtils.isNotBlank(System.getProperty("https.protocols"))) { + HttpClientBuilder httpClientBuilder = getHttpClientBuilder(); + return httpClientBuilder.build(); } else { return new DefaultHttpClient(params); } } - /** + private HttpClientBuilder getHttpClientBuilder() { + String protocols = System.getProperty("https.protocols"); + String[] protocolArray = protocols.split(","); + SSLContext sslContext = SSLContexts.createDefault(); + SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext, + protocolArray, + null, + new NoopHostnameVerifier()); + return HttpClients.custom().setSSLSocketFactory(sslsf); + } + + /** * Used to access the {@link AuthConfig} handler used to configure common * authentication mechanism. Example: *

builder.auth.basic( 'myUser', 'somePassword' )
@@ -957,9 +965,14 @@ public void shutdown() { getClient().getConnectionManager().shutdown(); } + void setCredentials(AuthScope authScope, UsernamePasswordCredentials credentials) { + BasicCredentialsProvider basicCredentialsProvider = new BasicCredentialsProvider(); + basicCredentialsProvider.setCredentials(authScope,credentials); + client = getHttpClientBuilder().setDefaultCredentialsProvider(basicCredentialsProvider).build(); + } - /** + /** *

Encloses all properties and method calls used within the * {@link HTTPBuilder#request(Object, Method, Object, Closure)} 'config' * closure argument. That is, an instance of this class is set as the