ProxyAuthTest.java revision 15880:a20f83221d20
152284Sobrien/*
252284Sobrien * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
352284Sobrien * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
452284Sobrien *
552284Sobrien * This code is free software; you can redistribute it and/or modify it
652284Sobrien * under the terms of the GNU General Public License version 2 only, as
752284Sobrien * published by the Free Software Foundation.
852284Sobrien *
952284Sobrien * This code is distributed in the hope that it will be useful, but WITHOUT
1052284Sobrien * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1152284Sobrien * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
1252284Sobrien * version 2 for more details (a copy is included in the LICENSE file that
1352284Sobrien * accompanied this code).
1452284Sobrien *
1552284Sobrien * You should have received a copy of the GNU General Public License version
1652284Sobrien * 2 along with this work; if not, write to the Free Software Foundation,
1752284Sobrien * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
1852284Sobrien *
1952284Sobrien * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2052284Sobrien * or visit www.oracle.com if you need additional information or have any
2152284Sobrien * questions.
2252284Sobrien */
2352284Sobrien
2452284Sobrien/*
2552284Sobrien * @test
2652284Sobrien * @bug 4323990 4413069 8160838
2752284Sobrien * @summary HttpsURLConnection doesn't send Proxy-Authorization on CONNECT
2852284Sobrien *     Incorrect checking of proxy server response
2952284Sobrien * @modules java.base/sun.net.www
3052284Sobrien * @library /javax/net/ssl/templates
3152284Sobrien * @run main/othervm ProxyAuthTest fail
3252284Sobrien * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic ProxyAuthTest fail
3352284Sobrien * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic, ProxyAuthTest fail
3452284Sobrien * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=BAsIc ProxyAuthTest fail
3552284Sobrien * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Basic,Digest ProxyAuthTest fail
3652284Sobrien * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Unknown,bAsIc ProxyAuthTest fail
3750397Sobrien * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes= ProxyAuthTest succeed
3850397Sobrien * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=Digest,NTLM,Negotiate ProxyAuthTest succeed
3950397Sobrien * @run main/othervm -Djdk.http.auth.tunneling.disabledSchemes=UNKNOWN,notKnown ProxyAuthTest succeed
4050397Sobrien */
4150397Sobrien
4250397Sobrien// No way to reserve and restore java.lang.Authenticator, as well as read-once
4350397Sobrien// system properties, so this tests needs to run in othervm mode.
4450397Sobrien
4550397Sobrienimport java.io.BufferedReader;
4650397Sobrienimport java.io.DataOutputStream;
4750397Sobrienimport java.io.IOException;
4850397Sobrienimport java.io.InputStreamReader;
4950397Sobrienimport java.net.Authenticator;
5050397Sobrienimport java.net.InetSocketAddress;
5150397Sobrienimport java.net.PasswordAuthentication;
5250397Sobrienimport java.net.Proxy;
5350397Sobrienimport java.net.URL;
5450397Sobrienimport javax.net.ssl.HostnameVerifier;
5550397Sobrienimport javax.net.ssl.HttpsURLConnection;
5650397Sobrienimport javax.net.ssl.SSLSession;
5750397Sobrienimport static java.nio.charset.StandardCharsets.US_ASCII;
5850397Sobrien
5950397Sobrien/*
6050397Sobrien * ProxyAuthTest.java -- includes a simple server that can serve
6150397Sobrien * Http get request in both clear and secure channel, and a client
6250397Sobrien * that makes https requests behind the firewall through an
6350397Sobrien * authentication proxy
6450397Sobrien */
6550397Sobrien
6650397Sobrienpublic class ProxyAuthTest {
6750397Sobrien    /*
6850397Sobrien     * Where do we find the keystores?
6950397Sobrien     */
7050397Sobrien    static String pathToStores = "../../../../../../javax/net/ssl/etc";
7150397Sobrien    static String keyStoreFile = "keystore";
7250397Sobrien    static String trustStoreFile = "truststore";
7350397Sobrien    static String passwd = "passphrase";
7450397Sobrien
7550397Sobrien    /**
7650397Sobrien     * read the response, don't care for the syntax of the request-line
7750397Sobrien     * for this testing
7850397Sobrien     */
7950397Sobrien    private static void readRequest(BufferedReader in) throws IOException {
8050397Sobrien        String line = null;
8150397Sobrien        System.out.println("Server received: ");
8250397Sobrien        do {
8350397Sobrien            if (line != null) {
8450397Sobrien                System.out.println(line);
8550397Sobrien            }
8650397Sobrien            line = in.readLine();
8750397Sobrien        } while ((line.length() != 0) &&
8850397Sobrien                (line.charAt(0) != '\r') && (line.charAt(0) != '\n'));
8950397Sobrien    }
9050397Sobrien
9150397Sobrien    /*
9250397Sobrien     * Main method to create the server and the client
9350397Sobrien     */
9450397Sobrien    public static void main(String args[]) throws Exception {
9550397Sobrien        boolean expectSuccess;
9650397Sobrien        expectSuccess = args[0].equals("succeed");
9750397Sobrien
9850397Sobrien        String keyFilename =
9950397Sobrien            SSLTest.TEST_SRC + "/" + pathToStores + "/" + keyStoreFile;
10050397Sobrien        String trustFilename =
10150397Sobrien            SSLTest.TEST_SRC + "/" + pathToStores + "/" + trustStoreFile;
10250397Sobrien
10350397Sobrien        SSLTest.setup(keyFilename, trustFilename, passwd);
10450397Sobrien
10550397Sobrien        new SSLTest()
10650397Sobrien            .setServerApplication((socket, test) -> {
10750397Sobrien                DataOutputStream out = new DataOutputStream(
10850397Sobrien                        socket.getOutputStream());
10950397Sobrien
11050397Sobrien                try {
11150397Sobrien                    BufferedReader in = new BufferedReader(
11250397Sobrien                            new InputStreamReader(socket.getInputStream()));
11350397Sobrien
11450397Sobrien                    // read the request
11550397Sobrien                    readRequest(in);
11650397Sobrien
11750397Sobrien                    // retrieve bytecodes
11850397Sobrien                    byte[] bytecodes =
11950397Sobrien                            "Proxy authentication for tunneling succeeded .."
12050397Sobrien                                    .getBytes(US_ASCII);
12150397Sobrien
12250397Sobrien                    // send bytecodes in response (assumes HTTP/1.0 or later)
12350397Sobrien                    out.writeBytes("HTTP/1.0 200 OK\r\n");
12450397Sobrien                    out.writeBytes("Content-Length: " + bytecodes.length +
12550397Sobrien                                   "\r\n");
12650397Sobrien                    out.writeBytes("Content-Type: text/html\r\n\r\n");
12750397Sobrien                    out.write(bytecodes);
12850397Sobrien                    out.flush();
12950397Sobrien                } catch (IOException e) {
13050397Sobrien                    // write out error response
13150397Sobrien                    out.writeBytes("HTTP/1.0 400 " + e.getMessage() + "\r\n");
13250397Sobrien                    out.writeBytes("Content-Type: text/html\r\n\r\n");
13350397Sobrien                    out.flush();
13450397Sobrien                }
13550397Sobrien            })
13650397Sobrien            .setClientPeer(test -> {
13750397Sobrien                try {
13850397Sobrien                    doClientSide(test);
13950397Sobrien                    if (!expectSuccess) {
14050397Sobrien                        throw new RuntimeException("Expected exception/failure "
14150397Sobrien                                + "to connect, but succeeded.");
14250397Sobrien                    }
14350397Sobrien                } catch (IOException e) {
14450397Sobrien                    if (expectSuccess) {
14550397Sobrien                        System.out.println("Client side failed: "
14650397Sobrien                                + e.getMessage());
14750397Sobrien                        throw e;
14850397Sobrien                    }
14950397Sobrien
15050397Sobrien                    if (! (e.getMessage().contains(
15150397Sobrien                                "Unable to tunnel through proxy") &&
15250397Sobrien                           e.getMessage().contains("407")) ) {
15350397Sobrien
15450397Sobrien                        throw new RuntimeException(
15550397Sobrien                                "Expected exception about cannot tunnel, "
15650397Sobrien                                        + "407, etc, but got", e);
15750397Sobrien                    } else {
15850397Sobrien                        // Informative
15950397Sobrien                        System.out.println("Caught expected exception: "
16050397Sobrien                                + e.getMessage());
16150397Sobrien                    }
16250397Sobrien                }
16350397Sobrien            })
16450397Sobrien            .runTest();
16550397Sobrien    }
16650397Sobrien
16750397Sobrien    static void doClientSide(SSLTest test) throws IOException {
16850397Sobrien
16950397Sobrien        // Wait for server to get started.
17050397Sobrien        //
17150397Sobrien        // The server side takes care of the issue if the server cannot
17250397Sobrien        // get started in 90 seconds.  The client side would just ignore
17350397Sobrien        // the test case if the serer is not ready.
17450397Sobrien        try {
17550397Sobrien            if (!test.waitForServerSignal()) {
17650397Sobrien                System.out.print("The server is not ready yet in 90 seconds. "
17750397Sobrien                        + "Ignore in client side.");
17850397Sobrien                return;
17950397Sobrien            }
18050397Sobrien        } catch (InterruptedException e) {
18150397Sobrien            System.out.print("InterruptedException occured. "
18250397Sobrien                    + "Ignore in client side.");
18350397Sobrien            return;
18450397Sobrien        }
18550397Sobrien
18650397Sobrien        /*
18750397Sobrien         * setup up a proxy with authentication information
18850397Sobrien         */
18950397Sobrien        ProxyTunnelServer ps = setupProxy();
19050397Sobrien
19150397Sobrien        /*
19250397Sobrien         * we want to avoid URLspoofCheck failures in cases where the cert
19350397Sobrien         * DN name does not match the hostname in the URL.
19450397Sobrien         */
19550397Sobrien        HttpsURLConnection.setDefaultHostnameVerifier(new NameVerifier());
19650397Sobrien
19750397Sobrien        InetSocketAddress paddr = new InetSocketAddress(
19850397Sobrien                "localhost", ps.getPort());
19950397Sobrien        Proxy proxy = new Proxy(Proxy.Type.HTTP, paddr);
20050397Sobrien
20150397Sobrien        URL url = new URL("https://" + "localhost:" + test.getServerPort()
20250397Sobrien                + "/index.html");
20350397Sobrien
20450397Sobrien        // Signal the server, the client is ready to communicate.
20550397Sobrien        test.signalClientReady();
20650397Sobrien
20750397Sobrien        HttpsURLConnection uc = (HttpsURLConnection) url.openConnection(proxy);
20850397Sobrien        try (BufferedReader in = new BufferedReader(
20950397Sobrien                new InputStreamReader(uc.getInputStream()))) {
21050397Sobrien
21150397Sobrien            String inputLine;
21250397Sobrien            System.out.print("Client recieved from the server: ");
21350397Sobrien            while ((inputLine = in.readLine()) != null) {
21450397Sobrien                System.out.println(inputLine);
21550397Sobrien            }
21650397Sobrien        } catch (IOException e) {
21750397Sobrien            // Assert that the error stream is not accessible from the failed
21850397Sobrien            // tunnel setup.
21950397Sobrien            if (uc.getErrorStream() != null) {
22050397Sobrien                throw new RuntimeException("Unexpected error stream.");
22150397Sobrien            }
22250397Sobrien
22350397Sobrien            throw e;
22450397Sobrien        }
22550397Sobrien    }
22650397Sobrien
22750397Sobrien    static class NameVerifier implements HostnameVerifier {
22850397Sobrien
22950397Sobrien        @Override
23050397Sobrien        public boolean verify(String hostname, SSLSession session) {
23150397Sobrien            return true;
23250397Sobrien        }
23350397Sobrien    }
23450397Sobrien
23550397Sobrien    static ProxyTunnelServer setupProxy() throws IOException {
23650397Sobrien        ProxyTunnelServer pserver = new ProxyTunnelServer();
23750397Sobrien        /*
23850397Sobrien         * register a system wide authenticator and setup the proxy for
23950397Sobrien         * authentication
24050397Sobrien         */
24150397Sobrien        Authenticator.setDefault(new TestAuthenticator());
24250397Sobrien
24350397Sobrien        // register with the username and password
24450397Sobrien        pserver.needUserAuth(true);
24550397Sobrien        pserver.setUserAuth("Test", "test123");
24650397Sobrien
24750397Sobrien        pserver.start();
24850397Sobrien        return pserver;
24950397Sobrien    }
25050397Sobrien
25150397Sobrien    public static class TestAuthenticator extends Authenticator {
25250397Sobrien
25350397Sobrien        @Override
25450397Sobrien        public PasswordAuthentication getPasswordAuthentication() {
25550397Sobrien            return new PasswordAuthentication("Test", "test123".toCharArray());
25650397Sobrien        }
25750397Sobrien    }
25850397Sobrien}
25950397Sobrien