From 49677d8dbc104c542be6772c84a8478917742dd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Richard=20K=C3=B6rber?= Date: Tue, 6 Mar 2018 22:11:05 +0100 Subject: [PATCH] Add support for Proxy connections --- .../main/java/org/shredzone/acme4j/Session.java | 17 +++++++++++++++++ .../acme4j/connector/DefaultConnection.java | 6 +++--- .../acme4j/connector/HttpConnector.java | 7 +++++-- .../provider/pebble/PebbleHttpConnector.java | 5 +++-- .../java/org/shredzone/acme4j/SessionTest.java | 10 ++++++++++ .../acme4j/connector/DefaultConnectionTest.java | 7 ++++--- .../acme4j/connector/HttpConnectorTest.java | 3 ++- src/site/markdown/usage/session.md | 8 ++++++++ 8 files changed, 52 insertions(+), 11 deletions(-) diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java b/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java index 6e0d947c..34231e93 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/Session.java @@ -13,6 +13,7 @@ */ package org.shredzone.acme4j; +import java.net.Proxy; import java.net.URI; import java.net.URL; import java.security.KeyPair; @@ -42,6 +43,7 @@ public class Session { private String nonce; private Locale locale = Locale.getDefault(); + private Proxy proxy = Proxy.NO_PROXY; protected Instant directoryCacheExpiry; /** @@ -128,6 +130,21 @@ public class Session { this.locale = locale; } + /** + * Gets the {@link Proxy} to be used for connections. + */ + public Proxy getProxy() { + return proxy; + } + + /** + * Sets a {@link Proxy} that is to be used for all connections. If {@code null}, + * {@link Proxy#NO_PROXY} is used, which is also the default. + */ + public void setProxy(Proxy proxy) { + this.proxy = proxy != null ? proxy : Proxy.NO_PROXY; + } + /** * Returns the {@link AcmeProvider} that is used for this session. * diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java index 79b78984..a2a910fd 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/DefaultConnection.java @@ -101,7 +101,7 @@ public class DefaultConnection implements Connection { URL newNonceUrl = session.resourceUrl(Resource.NEW_NONCE); - conn = httpConnector.openConnection(newNonceUrl); + conn = httpConnector.openConnection(newNonceUrl, session.getProxy()); conn.setRequestMethod("HEAD"); conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag()); conn.connect(); @@ -132,7 +132,7 @@ public class DefaultConnection implements Connection { LOG.debug("GET {}", url); try { - conn = httpConnector.openConnection(url); + conn = httpConnector.openConnection(url, session.getProxy()); conn.setRequestMethod("GET"); conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET); conn.setRequestProperty(ACCEPT_LANGUAGE_HEADER, session.getLocale().toLanguageTag()); @@ -311,7 +311,7 @@ public class DefaultConnection implements Connection { resetNonce(session); } - conn = httpConnector.openConnection(url); + conn = httpConnector.openConnection(url, session.getProxy()); conn.setRequestMethod("POST"); conn.setRequestProperty(ACCEPT_HEADER, "application/json"); conn.setRequestProperty(ACCEPT_CHARSET_HEADER, DEFAULT_CHARSET); diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/HttpConnector.java b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/HttpConnector.java index 2a89e01f..2191123d 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/connector/HttpConnector.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/connector/HttpConnector.java @@ -16,6 +16,7 @@ package org.shredzone.acme4j.connector; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; +import java.net.Proxy; import java.net.URL; import java.util.Properties; @@ -63,10 +64,12 @@ public class HttpConnector { * * @param url * {@link URL} to connect to + * @param proxy + * {@link Proxy} to be used * @return {@link HttpURLConnection} connected to the {@link URL} */ - public HttpURLConnection openConnection(URL url) throws IOException { - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + public HttpURLConnection openConnection(URL url, Proxy proxy) throws IOException { + HttpURLConnection conn = (HttpURLConnection) url.openConnection(proxy); configure(conn); return conn; } diff --git a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/PebbleHttpConnector.java b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/PebbleHttpConnector.java index c3b7d34e..42d39b7e 100644 --- a/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/PebbleHttpConnector.java +++ b/acme4j-client/src/main/java/org/shredzone/acme4j/provider/pebble/PebbleHttpConnector.java @@ -16,6 +16,7 @@ package org.shredzone.acme4j.provider.pebble; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; +import java.net.Proxy; import java.net.URL; import java.security.KeyManagementException; import java.security.KeyStore; @@ -39,8 +40,8 @@ public class PebbleHttpConnector extends HttpConnector { private static SSLSocketFactory sslSocketFactory; @Override - public HttpURLConnection openConnection(URL url) throws IOException { - HttpURLConnection conn = super.openConnection(url); + public HttpURLConnection openConnection(URL url, Proxy proxy) throws IOException { + HttpURLConnection conn = super.openConnection(url, proxy); if (conn instanceof HttpsURLConnection) { ((HttpsURLConnection) conn).setSSLSocketFactory(createSocketFactory()); } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/SessionTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/SessionTest.java index f1f0a225..c0cde219 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/SessionTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/SessionTest.java @@ -19,6 +19,9 @@ import static org.mockito.Mockito.*; import static org.shredzone.acme4j.toolbox.TestUtils.*; import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Proxy.Type; import java.net.URI; import java.net.URL; import java.security.KeyPair; @@ -79,6 +82,13 @@ public class SessionTest { session.setNonce(DUMMY_NONCE); assertThat(session.getNonce(), is(equalTo(DUMMY_NONCE))); + assertThat(session.getProxy(), is(Proxy.NO_PROXY)); + Proxy proxy = new Proxy(Type.HTTP, new InetSocketAddress("10.0.0.1", 8080)); + session.setProxy(proxy); + assertThat(session.getProxy(), is(proxy)); + session.setProxy(null); + assertThat(session.getProxy(), is(Proxy.NO_PROXY)); + assertThat(session.getServerUri(), is(serverUri)); } diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java index e3353edd..52238cd9 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/DefaultConnectionTest.java @@ -24,6 +24,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; +import java.net.Proxy; import java.net.URI; import java.net.URL; import java.security.KeyPair; @@ -78,7 +79,7 @@ public class DefaultConnectionTest { mockUrlConnection = mock(HttpURLConnection.class); mockHttpConnection = mock(HttpConnector.class); - when(mockHttpConnection.openConnection(requestUrl)).thenReturn(mockUrlConnection); + when(mockHttpConnection.openConnection(requestUrl, Proxy.NO_PROXY)).thenReturn(mockUrlConnection); final AcmeProvider mockProvider = mock(AcmeProvider.class); when(mockProvider.directory( @@ -158,7 +159,7 @@ public class DefaultConnectionTest { */ @Test public void testResetNonce() throws AcmeException, IOException { - when(mockHttpConnection.openConnection(new URL("https://example.com/acme/new-nonce"))) + when(mockHttpConnection.openConnection(new URL("https://example.com/acme/new-nonce"), Proxy.NO_PROXY)) .thenReturn(mockUrlConnection); when(mockUrlConnection.getResponseCode()) .thenReturn(HttpURLConnection.HTTP_NO_CONTENT); @@ -813,7 +814,7 @@ public class DefaultConnectionTest { */ @Test(expected = AcmeException.class) public void testSendSignedRequestNoNonce() throws Exception { - when(mockHttpConnection.openConnection(new URL("https://example.com/acme/new-nonce"))) + when(mockHttpConnection.openConnection(new URL("https://example.com/acme/new-nonce"), Proxy.NO_PROXY)) .thenReturn(mockUrlConnection); when(mockUrlConnection.getResponseCode()) .thenReturn(HttpURLConnection.HTTP_NOT_FOUND); diff --git a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/HttpConnectorTest.java b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/HttpConnectorTest.java index 48c0b145..a70d4636 100644 --- a/acme4j-client/src/test/java/org/shredzone/acme4j/connector/HttpConnectorTest.java +++ b/acme4j-client/src/test/java/org/shredzone/acme4j/connector/HttpConnectorTest.java @@ -20,6 +20,7 @@ import static org.mockito.Mockito.*; import java.io.IOException; import java.net.HttpURLConnection; +import java.net.Proxy; import java.net.URISyntaxException; import java.net.URL; @@ -59,7 +60,7 @@ public class HttpConnectorTest { @Category(HttpURLConnection.class) public void testOpenConnection() throws IOException { HttpConnector connector = new HttpConnector(); - HttpURLConnection conn = connector.openConnection(new URL("http://example.com")); + HttpURLConnection conn = connector.openConnection(new URL("http://example.com"), Proxy.NO_PROXY); assertThat(conn, not(nullValue())); conn.connect(); assertThat(conn.getResponseCode(), is(HttpURLConnection.HTTP_OK)); diff --git a/src/site/markdown/usage/session.md b/src/site/markdown/usage/session.md index 68ebdf35..701ec180 100644 --- a/src/site/markdown/usage/session.md +++ b/src/site/markdown/usage/session.md @@ -34,3 +34,11 @@ URL website = meta.getWebsite(); `Session.setLocale()` allows to select a different locale. Errors will be returned in that language, if supported by the CA. By default, the system's default locale is used. + +## Proxy + +_acme4j_ uses a standard `HttpURLConnection` for HTTP connections. + +If a proxy must be used for internet connections, you can set a `Proxy` instance by invoking `Session.setProxy()`. An alternative is to use the system properties `http.proxyHost` and `http.proxyPort` to globally set a proxy for the Java process. + +If the proxy needs authentication, you need to set a default `Authenticator`. Be careful: Most code snippets I have found in the internet will send out the proxy credentials to anyone who is asking. See [this blog article](http://rolandtapken.de/blog/2012-04/java-process-httpproxyuser-and-httpproxypassword) for a good way to implement a proxy `Authenticator`.