diff --git a/pom.xml b/pom.xml index 84646588..84e5e02b 100644 --- a/pom.xml +++ b/pom.xml @@ -2,24 +2,31 @@ 4.0.0 com.notnoop.apns apns - 1.0.0.Beta7-SNAPSHOT + 1.0.0.Beta7-EC-3.2.2-SNAPSHOT jar Java Apple Push Notification Service Library - - - org.sonatype.oss - oss-parent - 9 - - - scm:git:git://github.com/notnoop/java-apns.git - scm:git:git@github.com:notnoop/java-apns.git - http://github.com/notnoop/java-apns - HEAD + scm:git:git://github.com/encapsecurity/java-apns.git + scm:git:git@github.com:encapsecurity/java-apns.git + http://github.com/encapsecurity/java-apns + apns-1.0.0.Beta7-EC-3.2.0 + + + + encap-release-repo + https://test.encap.no/repository/content/repositories/releases + true + + + encap-snapshot-repo + https://test.encap.no/repository/content/repositories/snapshots + true + + + UTF-8 @@ -66,7 +73,7 @@ maven-jar-plugin 2.4 - + ${project.build.outputDirectory}/META-INF/MANIFEST.MF @@ -78,14 +85,14 @@ - + maven-javadoc-plugin 2.9.1 - + generate-javadoc @@ -125,9 +132,9 @@ bundle-manifest process-classes - + manifest - + @@ -260,9 +267,9 @@ --> - commons-httpclient - commons-httpclient - 3.1 + org.apache.httpcomponents + httpclient + 4.5.1 @@ -307,6 +314,12 @@ jar compile + + org.littleshoot + littleproxy + 1.1.0-beta1 + test + diff --git a/src/main/java/com/notnoop/apns/internal/TlsTunnelBuilder.java b/src/main/java/com/notnoop/apns/internal/TlsTunnelBuilder.java index 5e0d68cf..b84d0b07 100644 --- a/src/main/java/com/notnoop/apns/internal/TlsTunnelBuilder.java +++ b/src/main/java/com/notnoop/apns/internal/TlsTunnelBuilder.java @@ -35,16 +35,19 @@ import java.net.ProtocolException; import java.net.Proxy; import java.net.Socket; + import javax.net.ssl.SSLSocketFactory; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import org.apache.commons.httpclient.ConnectMethod; -import org.apache.commons.httpclient.NTCredentials; -import org.apache.commons.httpclient.ProxyClient; -import org.apache.commons.httpclient.UsernamePasswordCredentials; -import org.apache.commons.httpclient.auth.AuthScope; + +import org.apache.http.HttpHost; +import org.apache.http.auth.NTCredentials; +import org.apache.http.auth.UsernamePasswordCredentials; +import org.apache.http.impl.client.ProxyClient; +import org.apache.http.impl.execchain.TunnelRefusedException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; + /** * Establishes a TLS connection using an HTTP proxy. See RFC 2817 5.2. This class does @@ -87,27 +90,26 @@ Socket makeTunnel(String host, int port, String proxyUsername, logger.debug("Creating socket for Proxy : " + proxyAddress.getAddress() + ":" + proxyAddress.getPort()); Socket socket; try { - ProxyClient client = new ProxyClient(); - client.getParams().setParameter("http.useragent", "java-apns"); - client.getHostConfiguration().setHost(host, port); String proxyHost = proxyAddress.getAddress().toString().substring(0, proxyAddress.getAddress().toString().indexOf("/")); - client.getHostConfiguration().setProxy(proxyHost, proxyAddress.getPort()); + + HttpHost proxyHttpHost = new HttpHost(proxyHost, proxyAddress.getPort()); + HttpHost destHttpHost = new HttpHost(host, port); + ProxyClient proxyClient = new ProxyClient(); - - ProxyClient.ConnectResponse response = client.connect(); - socket = response.getSocket(); - if (socket == null) { - ConnectMethod method = response.getConnectMethod(); - // Read the proxy's HTTP response. - if(method.getStatusLine().getStatusCode() == 407) { - // Proxy server returned 407. We will now try to connect with auth Header - if(proxyUsername != null && proxyPassword != null) { - socket = AuthenticateProxy(method, client,proxyHost, proxyAddress.getPort(), - proxyUsername, proxyPassword); - } else { - throw new ProtocolException("Socket not created: " + method.getStatusLine()); - } - } + if (proxyUsername == null || proxyPassword == null) { + // Empty credentials created to fulfill api contract in case of proxy without credentials + UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("", ""); + socket = proxyClient.tunnel(proxyHttpHost, destHttpHost, credentials); + } else { + try { + UsernamePasswordCredentials cred = new UsernamePasswordCredentials(proxyUsername, proxyPassword); + socket = proxyClient.tunnel(proxyHttpHost, destHttpHost, cred); + } catch (TunnelRefusedException e) { + // To support NT credentials we try to connect once more + // Would be nicer to move the decision of which credentials to use + NTCredentials credentials = new NTCredentials(proxyUsername, proxyPassword, null, null); + socket = proxyClient.tunnel(proxyHttpHost, destHttpHost, credentials); + } } } catch (Exception e) { @@ -119,29 +121,4 @@ Socket makeTunnel(String host, int port, String proxyUsername, return socket; } - private Socket AuthenticateProxy(ConnectMethod method, ProxyClient client, - String proxyHost, int proxyPort, - String proxyUsername, String proxyPassword) throws IOException { - if("ntlm".equalsIgnoreCase(method.getProxyAuthState().getAuthScheme().getSchemeName())) { - // If Auth scheme is NTLM, set NT credentials with blank host and domain name - client.getState().setProxyCredentials(new AuthScope(proxyHost, proxyPort), - new NTCredentials(proxyUsername, proxyPassword,"","")); - } else { - // If Auth scheme is Basic/Digest, set regular Credentials - client.getState().setProxyCredentials(new AuthScope(proxyHost, proxyPort), - new UsernamePasswordCredentials(proxyUsername, proxyPassword)); - } - - ProxyClient.ConnectResponse response = client.connect(); - Socket socket = response.getSocket(); - - if (socket == null) { - method = response.getConnectMethod(); - throw new ProtocolException("Proxy Authentication failed. Socket not created: " - + method.getStatusLine()); - } - return socket; - } - } - diff --git a/src/test/java/com/notnoop/apns/internal/TlsTunnelBuilderTest.java b/src/test/java/com/notnoop/apns/internal/TlsTunnelBuilderTest.java index 833bed55..8d1796a6 100644 --- a/src/test/java/com/notnoop/apns/internal/TlsTunnelBuilderTest.java +++ b/src/test/java/com/notnoop/apns/internal/TlsTunnelBuilderTest.java @@ -30,48 +30,110 @@ */ package com.notnoop.apns.internal; -import java.io.ByteArrayInputStream; +import static org.junit.Assert.assertNotNull; + +import com.sun.net.httpserver.HttpServer; + import java.io.IOException; -import java.io.InputStream; -//import java.net.InetSocketAddress; -//import java.net.Proxy; -//import java.net.Socket; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Socket; +import java.net.UnknownHostException; + +import org.junit.After; +import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.fail; +import org.littleshoot.proxy.HttpProxyServer; +import org.littleshoot.proxy.ProxyAuthenticator; +import org.littleshoot.proxy.impl.DefaultHttpProxyServer; public class TlsTunnelBuilderTest { + private static final String PROXY_USERNAME = "proxy-username"; + private static final String PROXY_PASSWORD = "proxy-password"; + private TestHttpService testHttpService; + private String remoteHost; + private int remoteport = 9999; + private int localport = 8888; + private HttpProxyServer server; + + @Before + public void setUp() throws UnknownHostException { + + InetSocketAddress address = new InetSocketAddress(remoteport); + testHttpService = new TestHttpService(address); + remoteHost = address.getHostName(); + + server = DefaultHttpProxyServer.bootstrap() + .withProxyAuthenticator(new ProxyAuthenticator() { + @Override + public boolean authenticate(String userName, String password) { + return PROXY_USERNAME.equals(userName) && PROXY_PASSWORD.equals(password); + } + }) + .withPort(localport) + .start(); + } + + @After + public void tearDown() { + testHttpService.stop(); + server.stop(); + } + @Test public void makeTunnelSuccess() throws IOException { - /* Uncomment this test to verify with your proxy settings */ - /*try { - Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("proxy.mydomain.com", 8080)); - - InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address(); - Socket proxySocket = new Socket(proxyAddress.getAddress(), proxyAddress.getPort()); - InetSocketAddress destAddress = new InetSocketAddress("myhost.com", 2195); - - new TlsTunnelBuilder().makeTunnel(destAddress.getAddress().toString(), - destAddress.getPort(), - "proxy-username", "proxy-password", - proxyAddress); - } catch (IOException ex){ - fail(); - }*/ + /* Change host in this test to verify with your proxy settings */ + + Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", localport)); + + InetSocketAddress proxyAddress = (InetSocketAddress) proxy.address(); + Socket proxySocket = new Socket(proxyAddress.getAddress(), proxyAddress.getPort()); + assertNotNull(proxySocket); + proxySocket.close(); + + InetSocketAddress destAddress = new InetSocketAddress(remoteHost, remoteport); + + Socket remoteAddress = new Socket(destAddress.getAddress(), destAddress.getPort()); + assertNotNull(remoteAddress); + remoteAddress.close(); + + Socket socket = new TlsTunnelBuilder() + .makeTunnel( + remoteHost, + remoteport, + PROXY_USERNAME, + PROXY_PASSWORD, + proxyAddress); + assertNotNull(socket); } - @Test + @Test(expected = IOException.class) public void invalidProxyParams() throws IOException { - try { - new TlsTunnelBuilder().makeTunnel("origin.example.com", 9876, null, null, null); - fail(); - } catch (IOException expected) { - // No operation - } + new TlsTunnelBuilder().makeTunnel("origin.example.com", 9876, null, null, null); } - private InputStream inputStream(String content) throws IOException { - return new ByteArrayInputStream(content.getBytes("UTF-8")); + + public class TestHttpService { + + private HttpServer server; + + public TestHttpService(InetSocketAddress inetSocketAddress) { + try { + server = HttpServer.create(inetSocketAddress, 0); + server.createContext("/"); + server.setExecutor(null); + server.start(); + } catch (IOException e) { + throw new IllegalStateException("Could not get ip to localhost", e); + } + } + + public void stop() { + server.stop(0); + } + } + }