1 /* 2 * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.*; 25 import java.net.*; 26 import java.security.KeyStore; 27 import javax.net.*; 28 import javax.net.ssl.*; 29 30 import jdk.test.lib.process.OutputAnalyzer; 31 import jdk.test.lib.process.ProcessTools; 32 import jdk.test.lib.net.URIBuilder; 33 34 /* 35 * @test 36 * @bug 4423074 37 * @modules java.base/sun.net.www 38 * @summary This test case is written to test the https POST through a proxy 39 * with proxy authentication. It includes a simple server that serves 40 * http POST method requests in secure channel, and a client that 41 * makes https POST request through a proxy. 42 * @library /test/lib 43 * @build jdk.test.lib.Utils 44 * jdk.test.lib.Asserts 45 * jdk.test.lib.JDKToolFinder 46 * jdk.test.lib.JDKToolLauncher 47 * jdk.test.lib.Platform 48 * jdk.test.lib.process.* 49 * @compile OriginServer.java ProxyTunnelServer.java 50 * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes= PostThruProxyWithAuth 51 * @run main/othervm -Djava.net.preferIPv6Addresses=true 52 -Djdk.http.auth.tunneling.disabledSchemes= PostThruProxyWithAuth 53 */ 54 public class PostThruProxyWithAuth { 55 56 private static final String TEST_SRC = System.getProperty("test.src", "."); 57 private static final int TIMEOUT = 30000; 58 59 /* 60 * Where do we find the keystores? 61 */ 62 static String pathToStores = "../../../../../../javax/net/ssl/etc"; 63 static String keyStoreFile = "keystore"; 64 static String trustStoreFile = "truststore"; 65 static String passwd = "passphrase"; 66 67 volatile private static int serverPort = 0; 68 private static ProxyTunnelServer pserver; 69 private static TestServer server; 70 71 static final String RESPONSE_MSG = 72 "Https POST thru proxy is successful with proxy authentication"; 73 74 /* 75 * The TestServer implements a OriginServer that 76 * processes HTTP requests and responses. 77 */ 78 static class TestServer extends OriginServer { TestServer(ServerSocket ss)79 public TestServer(ServerSocket ss) throws Exception { 80 super(ss); 81 } 82 83 /* 84 * Returns an array of bytes containing the bytes for 85 * the data sent in the response. 86 * 87 * @return bytes for the data in the response 88 */ getBytes()89 public byte[] getBytes() { 90 return RESPONSE_MSG.getBytes(); 91 } 92 } 93 94 /* 95 * Main method to create the server and client 96 */ main(String args[])97 public static void main(String args[]) throws Exception { 98 String keyFilename = TEST_SRC + "/" + pathToStores + "/" + keyStoreFile; 99 String trustFilename = TEST_SRC + "/" + pathToStores + "/" 100 + trustStoreFile; 101 102 System.setProperty("javax.net.ssl.keyStore", keyFilename); 103 System.setProperty("javax.net.ssl.keyStorePassword", passwd); 104 System.setProperty("javax.net.ssl.trustStore", trustFilename); 105 System.setProperty("javax.net.ssl.trustStorePassword", passwd); 106 107 boolean useSSL = true; 108 /* 109 * setup the server 110 */ 111 try { 112 InetAddress localhost = InetAddress.getLocalHost(); 113 ServerSocketFactory ssf = getServerSocketFactory(useSSL); 114 ServerSocket ss = ssf.createServerSocket(serverPort, 0, localhost); 115 ss.setSoTimeout(TIMEOUT); // 30 seconds 116 serverPort = ss.getLocalPort(); 117 server = new TestServer(ss); 118 System.out.println("Server started at: " + ss); 119 } catch (Exception e) { 120 System.out.println("Server side failed:" + 121 e.getMessage()); 122 throw e; 123 } 124 // trigger the client 125 try { 126 doClientSide(); 127 } catch (Exception e) { 128 System.out.println("Client side failed: " + 129 e.getMessage()); 130 throw e; 131 } 132 long connectCount = pserver.getConnectCount(); 133 if (connectCount == 0) { 134 throw new AssertionError("Proxy was not used!"); 135 } else { 136 System.out.println("Proxy CONNECT count: " + connectCount); 137 } 138 } 139 getServerSocketFactory(boolean useSSL)140 private static ServerSocketFactory getServerSocketFactory 141 (boolean useSSL) throws Exception { 142 if (useSSL) { 143 // set up key manager to do server authentication 144 SSLContext ctx = SSLContext.getInstance("TLS"); 145 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); 146 KeyStore ks = KeyStore.getInstance("JKS"); 147 char[] passphrase = passwd.toCharArray(); 148 149 ks.load(new FileInputStream(System.getProperty( 150 "javax.net.ssl.keyStore")), passphrase); 151 kmf.init(ks, passphrase); 152 ctx.init(kmf.getKeyManagers(), null, null); 153 154 return ctx.getServerSocketFactory(); 155 } else { 156 return ServerSocketFactory.getDefault(); 157 } 158 } 159 160 /* 161 * Message to be posted 162 */ 163 static String postMsg = "Testing HTTP post on a https server"; 164 doClientSide()165 static void doClientSide() throws Exception { 166 /* 167 * setup up a proxy 168 */ 169 SocketAddress pAddr = setupProxy(); 170 171 /* 172 * we want to avoid URLspoofCheck failures in cases where the cert 173 * DN name does not match the hostname in the URL. 174 */ 175 HttpsURLConnection.setDefaultHostnameVerifier( 176 new NameVerifier()); 177 178 URL url = URIBuilder.newBuilder() 179 .scheme("https") 180 .host(getHostname()) 181 .port(serverPort) 182 .toURL(); 183 184 Proxy p = new Proxy(Proxy.Type.HTTP, pAddr); 185 System.out.println("Client connecting to: " + url); 186 System.out.println("Through proxy: " + pAddr); 187 HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p); 188 https.setConnectTimeout(TIMEOUT); 189 https.setReadTimeout(TIMEOUT); 190 https.setDoOutput(true); 191 https.setRequestMethod("POST"); 192 PrintStream ps = null; 193 try { 194 ps = new PrintStream(https.getOutputStream()); 195 ps.println(postMsg); 196 ps.flush(); 197 if (https.getResponseCode() != 200) { 198 throw new RuntimeException("test Failed"); 199 } 200 ps.close(); 201 // clear the pipe 202 BufferedReader in = new BufferedReader( 203 new InputStreamReader( 204 https.getInputStream())); 205 String inputLine; 206 boolean msgFound = false; 207 while ((inputLine = in.readLine()) != null) { 208 System.out.println("Client received: " + inputLine); 209 if (inputLine.contains(RESPONSE_MSG)) msgFound = true; 210 } 211 in.close(); 212 if (!msgFound) { 213 throw new RuntimeException("POST message not found."); 214 } 215 } catch (SSLException e) { 216 if (ps != null) 217 ps.close(); 218 throw e; 219 } catch (SocketTimeoutException e) { 220 System.out.println("Client can not get response in time: " 221 + e.getMessage()); 222 } 223 } 224 225 static class NameVerifier implements HostnameVerifier { verify(String hostname, SSLSession session)226 public boolean verify(String hostname, SSLSession session) { 227 return true; 228 } 229 } 230 setupProxy()231 static SocketAddress setupProxy() throws IOException { 232 233 InetAddress localhost = InetAddress.getLocalHost(); 234 pserver = new ProxyTunnelServer(localhost); 235 236 /* 237 * register a system wide authenticator and setup the proxy for 238 * authentication 239 */ 240 Authenticator.setDefault(new TestAuthenticator()); 241 242 // register with the username and password 243 pserver.needUserAuth(true); 244 pserver.setUserAuth("Test", "test123"); 245 246 pserver.start(); 247 248 return new InetSocketAddress(localhost, pserver.getPort()); 249 } 250 251 public static class TestAuthenticator extends Authenticator { getPasswordAuthentication()252 public PasswordAuthentication getPasswordAuthentication() { 253 return new PasswordAuthentication("Test", 254 "test123".toCharArray()); 255 } 256 } 257 getHostname()258 private static String getHostname() { 259 try { 260 OutputAnalyzer oa = ProcessTools.executeCommand("hostname"); 261 return oa.getOutput().trim(); 262 } catch (Throwable e) { 263 throw new RuntimeException("Get hostname failed.", e); 264 } 265 } 266 } 267