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