1 /*
   2  * Copyright (c) 2001, 2016, 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 
  33 /*
  34  * @test
  35  * @bug 4423074
  36  * @modules java.base/sun.net.www
  37  * @summary This test case is written to test the https POST through a proxy.
  38  *          There is no proxy authentication done. It includes a simple server
  39  *          that serves http POST method requests in secure channel, and a client
  40  *          that makes https POST request through a proxy.
  41  * @library /test/lib
  42  * @build jdk.test.lib.Utils
  43  *        jdk.test.lib.Asserts
  44  *        jdk.test.lib.JDKToolFinder
  45  *        jdk.test.lib.JDKToolLauncher
  46  *        jdk.test.lib.Platform
  47  *        jdk.test.lib.process.*
  48  * @compile OriginServer.java ProxyTunnelServer.java
  49  * @run main/othervm PostThruProxy
  50  */
  51 public class PostThruProxy {
  52 
  53     private static final String TEST_SRC = System.getProperty("test.src", ".");
  54     private static final int TIMEOUT = 30000;
  55 
  56     /*
  57      * Where do we find the keystores?
  58      */
  59     static String pathToStores = "../../../../../../javax/net/ssl/etc";
  60     static String keyStoreFile = "keystore";
  61     static String trustStoreFile = "truststore";
  62     static String passwd = "passphrase";
  63 
  64     private static int serverPort = 0;
  65 
  66     /*
  67      * The TestServer implements a OriginServer that
  68      * processes HTTP requests and responses.
  69      */
  70     static class TestServer extends OriginServer {
  71         public TestServer(ServerSocket ss) throws Exception {
  72             super(ss);
  73         }
  74 
  75         /*
  76          * Returns an array of bytes containing the bytes for
  77          * the data sent in the response.
  78          *
  79          * @return bytes for the data in the response
  80          */
  81         public byte[] getBytes() {
  82             return "Https POST thru proxy is successful".
  83                         getBytes();
  84         }
  85     }
  86 
  87     /*
  88      * Main method to create the server and client
  89      */
  90     public static void main(String args[]) throws Exception {
  91         String keyFilename = TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
  92         String trustFilename = TEST_SRC + "/" + pathToStores + "/"
  93                 + trustStoreFile;
  94 
  95         System.setProperty("javax.net.ssl.keyStore", keyFilename);
  96         System.setProperty("javax.net.ssl.keyStorePassword", passwd);
  97         System.setProperty("javax.net.ssl.trustStore", trustFilename);
  98         System.setProperty("javax.net.ssl.trustStorePassword", passwd);
  99 
 100         boolean useSSL = true;
 101         /*
 102          * setup the server
 103          */
 104         try {
 105             ServerSocketFactory ssf = getServerSocketFactory(useSSL);
 106             ServerSocket ss = ssf.createServerSocket(serverPort);
 107             ss.setSoTimeout(TIMEOUT);  // 30 seconds
 108             serverPort = ss.getLocalPort();
 109             new TestServer(ss);
 110         } catch (Exception e) {
 111             System.out.println("Server side failed:" +
 112                                 e.getMessage());
 113             throw e;
 114         }
 115         // trigger the client
 116         try {
 117             doClientSide();
 118         } catch (Exception e) {
 119             System.out.println("Client side failed: " +
 120                                 e.getMessage());
 121             throw e;
 122         }
 123     }
 124 
 125     private static ServerSocketFactory getServerSocketFactory
 126                    (boolean useSSL) throws Exception {
 127         if (useSSL) {
 128             // set up key manager to do server authentication
 129             SSLContext ctx = SSLContext.getInstance("TLS");
 130             KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 131             KeyStore ks = KeyStore.getInstance("JKS");
 132             char[] passphrase = passwd.toCharArray();
 133 
 134             ks.load(new FileInputStream(System.getProperty(
 135                         "javax.net.ssl.keyStore")), passphrase);
 136             kmf.init(ks, passphrase);
 137             ctx.init(kmf.getKeyManagers(), null, null);
 138 
 139             return ctx.getServerSocketFactory();
 140         } else {
 141             return ServerSocketFactory.getDefault();
 142         }
 143     }
 144 
 145     /*
 146      * Message to be posted
 147      */
 148     static String postMsg = "Testing HTTP post on a https server";
 149 
 150     static void doClientSide() throws Exception {
 151         HostnameVerifier reservedHV =
 152             HttpsURLConnection.getDefaultHostnameVerifier();
 153         try {
 154             /*
 155              * setup up a proxy
 156              */
 157             SocketAddress pAddr = setupProxy();
 158 
 159             /*
 160              * we want to avoid URLspoofCheck failures in cases where the cert
 161              * DN name does not match the hostname in the URL.
 162              */
 163             HttpsURLConnection.setDefaultHostnameVerifier(
 164                                           new NameVerifier());
 165             URL url = new URL("https://" + getHostname() +":" + serverPort);
 166 
 167             Proxy p = new Proxy(Proxy.Type.HTTP, pAddr);
 168             HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p);
 169             https.setConnectTimeout(TIMEOUT);
 170             https.setReadTimeout(TIMEOUT);
 171             https.setDoOutput(true);
 172             https.setRequestMethod("POST");
 173             PrintStream ps = null;
 174             try {
 175                ps = new PrintStream(https.getOutputStream());
 176                ps.println(postMsg);
 177                ps.flush();
 178                if (https.getResponseCode() != 200) {
 179                     throw new RuntimeException("test Failed");
 180                }
 181                ps.close();
 182 
 183                // clear the pipe
 184                BufferedReader in = new BufferedReader(
 185                                     new InputStreamReader(
 186                                     https.getInputStream()));
 187                String inputLine;
 188                while ((inputLine = in.readLine()) != null)
 189                     System.out.println("Client received: " + inputLine);
 190                in.close();
 191             } catch (SSLException e) {
 192                 if (ps != null)
 193                     ps.close();
 194                 throw e;
 195             } catch (SocketTimeoutException e) {
 196                 System.out.println("Client can not get response in time: "
 197                         + e.getMessage());
 198             }
 199         } finally {
 200             HttpsURLConnection.setDefaultHostnameVerifier(reservedHV);
 201         }
 202     }
 203 
 204     static class NameVerifier implements HostnameVerifier {
 205         public boolean verify(String hostname, SSLSession session) {
 206             return true;
 207         }
 208     }
 209 
 210     static SocketAddress setupProxy() throws IOException {
 211         ProxyTunnelServer pserver = new ProxyTunnelServer();
 212 
 213         // disable proxy authentication
 214         pserver.needUserAuth(false);
 215         pserver.start();
 216         return new InetSocketAddress("localhost", pserver.getPort());
 217     }
 218 
 219     private static String getHostname() {
 220         try {
 221             OutputAnalyzer oa = ProcessTools.executeCommand("hostname");
 222             return oa.getOutput().trim();
 223         } catch (Throwable e) {
 224             throw new RuntimeException("Get hostname failed.", e);
 225         }
 226     }
 227 }