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
24import java.io.*;
25import java.net.*;
26import java.security.KeyStore;
27import javax.net.*;
28import javax.net.ssl.*;
29
30import jdk.test.lib.process.OutputAnalyzer;
31import 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 */
51public 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}
238