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 /*
  25  * @test
  26  * @bug 4323990 4413069
  27  * @summary HttpsURLConnection doesn't send Proxy-Authorization on CONNECT
  28  *     Incorrect checking of proxy server response
  29  * @modules java.base/sun.net.www
  30  * @library /javax/net/ssl/templates
  31  * @run main/othervm ProxyAuthTest
  32  *
  33  *     No way to reserve and restore java.lang.Authenticator, need to run this
  34  *     test in othervm mode.
  35  */
  36 
  37 import java.io.*;
  38 import java.net.*;
  39 import javax.net.ssl.*;
  40 
  41 /*
  42  * ProxyAuthTest.java -- includes a simple server that can serve
  43  * Http get request in both clear and secure channel, and a client
  44  * that makes https requests behind the firewall through an
  45  * authentication proxy
  46  */
  47 
  48 public class ProxyAuthTest {
  49     /*
  50      * Where do we find the keystores?
  51      */
  52     static String pathToStores = "../../../../../../javax/net/ssl/etc";
  53     static String keyStoreFile = "keystore";
  54     static String trustStoreFile = "truststore";
  55     static String passwd = "passphrase";
  56 
  57     /**
  58      * read the response, don't care for the syntax of the request-line
  59      * for this testing
  60      */
  61     private static void readRequest(BufferedReader in) throws IOException {
  62         String line = null;
  63         System.out.println("Server received: ");
  64         do {
  65             if (line != null) {
  66                 System.out.println(line);
  67             }
  68             line = in.readLine();
  69         } while ((line.length() != 0) &&
  70                 (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
  71     }
  72 
  73 
  74     /*
  75      * Main method to create the server and the client
  76      */
  77     public static void main(String args[]) throws Exception {
  78         String keyFilename =
  79             SSLTest.TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
  80         String trustFilename =
  81             SSLTest.TEST_SRC + "/" + pathToStores + "/" + trustStoreFile;
  82 
  83         SSLTest.setup(keyFilename, trustFilename, passwd);
  84 
  85         new SSLTest()
  86             .setServerApplication((socket, test) -> {
  87                 DataOutputStream out = new DataOutputStream(
  88                         socket.getOutputStream());
  89                 try {
  90                     BufferedReader in = new BufferedReader(
  91                             new InputStreamReader(socket.getInputStream()));
  92 
  93                     // read the request
  94                     readRequest(in);
  95 
  96                     // retrieve bytecodes
  97                     byte[] bytecodes =
  98                             "Proxy authentication for tunneling succeeded .."
  99                                     .getBytes();
 100 
 101                     // send bytecodes in response (assumes HTTP/1.0 or later)
 102                     out.writeBytes("HTTP/1.0 200 OK\r\n");
 103                     out.writeBytes("Content-Length: " + bytecodes.length +
 104                                    "\r\n");
 105                     out.writeBytes("Content-Type: text/html\r\n\r\n");
 106                     out.write(bytecodes);
 107                     out.flush();
 108                 } catch (Exception e) {
 109                     // write out error response
 110                     out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
 111                     out.writeBytes("Content-Type: text/html\r\n\r\n");
 112                     out.flush();
 113                 }
 114             })
 115             .setClientPeer(test -> {
 116                 doClientSide(test);
 117             })
 118             .runTest();
 119     }
 120 
 121     private static void doClientSide(SSLTest test) throws Exception {
 122 
 123         // Wait for server to get started.
 124         //
 125         // The server side takes care of the issue if the server cannot
 126         // get started in 90 seconds.  The client side would just ignore
 127         // the test case if the serer is not ready.
 128         if (!test.waitForServerSignal()) {
 129             System.out.print("The server is not ready yet in 90 seconds. "
 130                     + "Ignore in client side.");
 131             return;
 132         }
 133 
 134         /*
 135          * setup up a proxy with authentication information
 136          */
 137         setupProxy();
 138 
 139         /*
 140          * we want to avoid URLspoofCheck failures in cases where the cert
 141          * DN name does not match the hostname in the URL.
 142          */
 143         HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
 144 
 145         URL url = new URL("https://" + "localhost:" + test.getServerPort()
 146                 + "/index.html");
 147 
 148         // Signal the server, the client is ready to communicate.
 149         test.signalClientReady();
 150 
 151         try (BufferedReader in = new BufferedReader(
 152                 new InputStreamReader(url.openStream()))) {
 153 
 154             String inputLine;
 155             System.out.print("Client recieved from the server: ");
 156             while ((inputLine = in.readLine()) != null) {
 157                 System.out.println(inputLine);
 158             }
 159         }
 160     }
 161 
 162     static class NameVerifier implements HostnameVerifier {
 163 
 164         @Override
 165         public boolean verify(String hostname, SSLSession session) {
 166             return true;
 167         }
 168     }
 169 
 170     static void setupProxy() throws IOException {
 171         ProxyTunnelServer pserver = new ProxyTunnelServer();
 172         /*
 173          * register a system wide authenticator and setup the proxy for
 174          * authentication
 175          */
 176         Authenticator.setDefault(new TestAuthenticator());
 177 
 178         // register with the username and password
 179         pserver.needUserAuth(true);
 180         pserver.setUserAuth("Test", "test123");
 181 
 182         pserver.start();
 183         System.setProperty("https.proxyHost", "localhost");
 184         System.setProperty("https.proxyPort",
 185                 String.valueOf(pserver.getPort()));
 186     }
 187 
 188     public static class TestAuthenticator extends Authenticator {
 189 
 190         @Override
 191         public PasswordAuthentication getPasswordAuthentication() {
 192             return new PasswordAuthentication("Test", "test123".toCharArray());
 193         }
 194     }
 195 }