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  *          with proxy authentication. It includes a simple server that serves
  39  *          http POST method requests in secure channel, and a client that
  40  *          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 -Djdk.http.auth.tunneling.disabledSchemes= PostThruProxyWithAuth
  50  */
  51 public class PostThruProxyWithAuth {
  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     volatile 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
  83                 "Https POST thru proxy is successful with proxy authentication".
  84                 getBytes();
  85         }
  86     }
  87 
  88     /*
  89      * Main method to create the server and client
  90      */
  91     public static void main(String args[]) throws Exception {
  92         String keyFilename = TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
  93         String trustFilename = TEST_SRC + "/" + pathToStores + "/"
  94                 + trustStoreFile;
  95 
  96         System.setProperty("javax.net.ssl.keyStore", keyFilename);
  97         System.setProperty("javax.net.ssl.keyStorePassword", passwd);
  98         System.setProperty("javax.net.ssl.trustStore", trustFilename);
  99         System.setProperty("javax.net.ssl.trustStorePassword", passwd);
 100 
 101         boolean useSSL = true;
 102         /*
 103          * setup the server
 104          */
 105         try {
 106             ServerSocketFactory ssf = getServerSocketFactory(useSSL);
 107             ServerSocket ss = ssf.createServerSocket(serverPort);
 108             ss.setSoTimeout(TIMEOUT);  // 30 seconds
 109             serverPort = ss.getLocalPort();
 110             new TestServer(ss);
 111         } catch (Exception e) {
 112             System.out.println("Server side failed:" +
 113                                 e.getMessage());
 114             throw e;
 115         }
 116         // trigger the client
 117         try {
 118             doClientSide();
 119         } catch (Exception e) {
 120             System.out.println("Client side failed: " +
 121                                 e.getMessage());
 122             throw e;
 123           }
 124     }
 125 
 126     private static ServerSocketFactory getServerSocketFactory
 127                    (boolean useSSL) throws Exception {
 128         if (useSSL) {
 129             // set up key manager to do server authentication
 130             SSLContext ctx = SSLContext.getInstance("TLS");
 131             KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 132             KeyStore ks = KeyStore.getInstance("JKS");
 133             char[] passphrase = passwd.toCharArray();
 134 
 135             ks.load(new FileInputStream(System.getProperty(
 136                         "javax.net.ssl.keyStore")), passphrase);
 137             kmf.init(ks, passphrase);
 138             ctx.init(kmf.getKeyManagers(), null, null);
 139 
 140             return ctx.getServerSocketFactory();
 141         } else {
 142             return ServerSocketFactory.getDefault();
 143         }
 144     }
 145 
 146     /*
 147      * Message to be posted
 148      */
 149     static String postMsg = "Testing HTTP post on a https server";
 150 
 151     static void doClientSide() throws Exception {
 152         /*
 153          * setup up a proxy
 154          */
 155         SocketAddress pAddr = setupProxy();
 156 
 157         /*
 158          * we want to avoid URLspoofCheck failures in cases where the cert
 159          * DN name does not match the hostname in the URL.
 160          */
 161         HttpsURLConnection.setDefaultHostnameVerifier(
 162                                       new NameVerifier());
 163         URL url = new URL("https://" + getHostname() + ":" + serverPort);
 164 
 165         Proxy p = new Proxy(Proxy.Type.HTTP, pAddr);
 166         HttpsURLConnection https = (HttpsURLConnection)url.openConnection(p);
 167         https.setConnectTimeout(TIMEOUT);
 168         https.setReadTimeout(TIMEOUT);
 169         https.setDoOutput(true);
 170         https.setRequestMethod("POST");
 171         PrintStream ps = null;
 172         try {
 173            ps = new PrintStream(https.getOutputStream());
 174            ps.println(postMsg);
 175            ps.flush();
 176            if (https.getResponseCode() != 200) {
 177                 throw new RuntimeException("test Failed");
 178            }
 179            ps.close();
 180            // clear the pipe
 181            BufferedReader in = new BufferedReader(
 182                                 new InputStreamReader(
 183                                 https.getInputStream()));
 184            String inputLine;
 185            while ((inputLine = in.readLine()) != null)
 186                  System.out.println("Client received: " + inputLine);
 187            in.close();
 188         } catch (SSLException e) {
 189             if (ps != null)
 190                 ps.close();
 191             throw e;
 192         } catch (SocketTimeoutException e) {
 193             System.out.println("Client can not get response in time: "
 194                     + e.getMessage());
 195         }
 196     }
 197 
 198     static class NameVerifier implements HostnameVerifier {
 199         public boolean verify(String hostname, SSLSession session) {
 200             return true;
 201         }
 202     }
 203 
 204     static SocketAddress setupProxy() throws IOException {
 205         ProxyTunnelServer pserver = new ProxyTunnelServer();
 206 
 207         /*
 208          * register a system wide authenticator and setup the proxy for
 209          * authentication
 210          */
 211         Authenticator.setDefault(new TestAuthenticator());
 212 
 213         // register with the username and password
 214         pserver.needUserAuth(true);
 215         pserver.setUserAuth("Test", "test123");
 216 
 217         pserver.start();
 218 
 219         return new InetSocketAddress("localhost", pserver.getPort());
 220     }
 221 
 222     public static class TestAuthenticator extends Authenticator {
 223         public PasswordAuthentication getPasswordAuthentication() {
 224             return new PasswordAuthentication("Test",
 225                                          "test123".toCharArray());
 226         }
 227     }
 228 
 229     private static String getHostname() {
 230         try {
 231             OutputAnalyzer oa = ProcessTools.executeCommand("hostname");
 232             return oa.getOutput().trim();
 233         } catch (Throwable e) {
 234             throw new RuntimeException("Get hostname failed.", e);
 235         }
 236     }
 237 }