1 /* 2 * Copyright (c) 2016, 2017, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 import java.io.IOException; 27 import java.net.Authenticator; 28 import java.net.HttpURLConnection; 29 import java.net.Proxy; 30 import java.net.URL; 31 import java.util.Arrays; 32 import java.util.stream.Collectors; 33 import java.util.stream.Stream; 34 35 /* 36 * @test 37 * @bug 8169415 38 * @library /lib/testlibrary/ 39 * @modules java.logging 40 * java.base/sun.net.www 41 * java.base/sun.net.www.protocol.http 42 * jdk.httpserver/sun.net.httpserver 43 * @build jdk.testlibrary.SimpleSSLContext HTTPTest HTTPTestServer HTTPTestClient HTTPSetAuthenticatorTest 44 * @summary A simple HTTP test that starts an echo server supporting the given 45 * authentication scheme, then starts a regular HTTP client to invoke it. 46 * The client first does a GET request on "/", then follows on 47 * with a POST request that sends "Hello World!" to the server. 48 * The client expects to receive "Hello World!" in return. 49 * The test supports several execution modes: 50 * SERVER: The server performs Server authentication; 51 * PROXY: The server pretends to be a proxy and performs 52 * Proxy authentication; 53 * SERVER307: The server redirects the client (307) to another 54 * server that perform Server authentication; 55 * PROXY305: The server attempts to redirect 56 * the client to a proxy using 305 code; 57 * This test runs the client several times, providing different 58 * authenticators to the HttpURLConnection and verifies that 59 * the authenticator is invoked as expected - validating that 60 * connections with different authenticators do not share each 61 * other's socket channel and authentication info. 62 * Note: BASICSERVER means that the server will let the underlying 63 * com.sun.net.httpserver.HttpServer perform BASIC 64 * authentication when in Server mode. There should be 65 * no real difference between BASICSERVER and BASIC - it should 66 * be transparent on the client side. 67 * @run main/othervm HTTPSetAuthenticatorTest NONE SERVER PROXY SERVER307 PROXY305 68 * @run main/othervm HTTPSetAuthenticatorTest DIGEST SERVER 69 * @run main/othervm HTTPSetAuthenticatorTest DIGEST PROXY 70 * @run main/othervm HTTPSetAuthenticatorTest DIGEST PROXY305 71 * @run main/othervm HTTPSetAuthenticatorTest DIGEST SERVER307 72 * @run main/othervm HTTPSetAuthenticatorTest BASIC SERVER 73 * @run main/othervm HTTPSetAuthenticatorTest BASIC PROXY 74 * @run main/othervm HTTPSetAuthenticatorTest BASIC PROXY305 75 * @run main/othervm HTTPSetAuthenticatorTest BASIC SERVER307 76 * @run main/othervm HTTPSetAuthenticatorTest BASICSERVER SERVER 77 * @run main/othervm HTTPSetAuthenticatorTest BASICSERVER SERVER307 78 * 79 * @author danielfuchs 80 */ 81 public class HTTPSetAuthenticatorTest extends HTTPTest { 82 83 public static void main(String[] args) throws Exception { 84 String[] schemes; 85 String[] params; 86 if (args == null || args.length == 0) { 87 schemes = Stream.of(HttpSchemeType.values()) 88 .map(HttpSchemeType::name) 89 .collect(Collectors.toList()) 90 .toArray(new String[0]); 91 params = new String[0]; 92 } else { 93 schemes = new String[] { args[0] }; 94 params = Arrays.copyOfRange(args, 1, args.length); 95 } 96 for (String scheme : schemes) { 97 System.out.println("==== Testing with scheme=" + scheme + " ====\n"); 98 new HTTPSetAuthenticatorTest(HttpSchemeType.valueOf(scheme)) 99 .execute(params); 100 System.out.println(); 101 } 102 } 103 104 final HttpSchemeType scheme; 105 public HTTPSetAuthenticatorTest(HttpSchemeType scheme) { 106 this.scheme = scheme; 107 } 108 109 @Override 110 public HttpSchemeType getHttpSchemeType() { 111 return scheme; 112 } 113 114 @Override 115 public int run(HTTPTestServer server, 116 HttpProtocolType protocol, 117 HttpAuthType mode) 118 throws IOException 119 { 120 HttpTestAuthenticator authOne = new HttpTestAuthenticator("dublin", "foox"); 121 HttpTestAuthenticator authTwo = new HttpTestAuthenticator("dublin", "foox"); 122 int expectedIncrement = scheme == HttpSchemeType.NONE 123 ? 0 : EXPECTED_AUTH_CALLS_PER_TEST; 124 int count; 125 int defaultCount = AUTHENTICATOR.count.get(); 126 127 // Connect to the server with a GET request, then with a 128 // POST that contains "Hello World!" 129 // Uses authenticator #1 130 System.out.println("\nClient: Using authenticator #1: " 131 + toString(authOne)); 132 HTTPTestClient.connect(protocol, server, mode, authOne); 133 count = authOne.count.get(); 134 if (count != expectedIncrement) { 135 throw new AssertionError("Authenticator #1 called " + count(count) 136 + " expected it to be called " + expected(expectedIncrement)); 137 } 138 139 // Connect to the server with a GET request, then with a 140 // POST that contains "Hello World!" 141 // Uses authenticator #2 142 System.out.println("\nClient: Using authenticator #2: " 143 + toString(authTwo)); 144 HTTPTestClient.connect(protocol, server, mode, authTwo); 145 count = authTwo.count.get(); 146 if (count != expectedIncrement) { 147 throw new AssertionError("Authenticator #2 called " + count(count) 148 + " expected it to be called " + expected(expectedIncrement)); 149 } 150 151 // Connect to the server with a GET request, then with a 152 // POST that contains "Hello World!" 153 // Uses authenticator #1 154 System.out.println("\nClient: Using authenticator #1 again: " 155 + toString(authOne)); 156 HTTPTestClient.connect(protocol, server, mode, authOne); 157 count = authOne.count.get(); 158 if (count != expectedIncrement) { 159 throw new AssertionError("Authenticator #1 called " + count(count) 160 + " expected it to be called " + expected(expectedIncrement)); 161 } 162 count = authTwo.count.get(); 163 if (count != expectedIncrement) { 164 throw new AssertionError("Authenticator #2 called " + count(count) 165 + " expected it to be called " + expected(expectedIncrement)); 166 } 167 count = AUTHENTICATOR.count.get(); 168 if (count != defaultCount) { 169 throw new AssertionError("Default Authenticator called " + count(count) 170 + " expected it to be called " + expected(defaultCount)); 171 } 172 173 // Now tries with the default authenticator: it should be invoked. 174 System.out.println("\nClient: Using the default authenticator: " 175 + toString(null)); 176 HTTPTestClient.connect(protocol, server, mode, null); 177 count = authOne.count.get(); 178 if (count != expectedIncrement) { 179 throw new AssertionError("Authenticator #1 called " + count(count) 180 + " expected it to be called " + expected(expectedIncrement)); 181 } 182 count = authTwo.count.get(); 183 if (count != expectedIncrement) { 184 throw new AssertionError("Authenticator #2 called " + count(count) 185 + " expected it to be called " + expected(expectedIncrement)); 186 } 187 count = AUTHENTICATOR.count.get(); 188 if (count != defaultCount + expectedIncrement) { 189 throw new AssertionError("Default Authenticator called " + count(count) 190 + " expected it to be called " + expected(defaultCount + expectedIncrement)); 191 } 192 193 // Now tries with explicitly setting the default authenticator: it should 194 // be invoked again. 195 // Uncomment the code below when 8169068 is available. 196 // System.out.println("\nClient: Explicitly setting the default authenticator: " 197 // + toString(Authenticator.getDefault())); 198 // HTTPTestClient.connect(protocol, server, mode, Authenticator.getDefault()); 199 // count = authOne.count.get(); 200 // if (count != expectedIncrement) { 201 // throw new AssertionError("Authenticator #1 called " + count(count) 202 // + " expected it to be called " + expected(expectedIncrement)); 203 // } 204 // count = authTwo.count.get(); 205 // if (count != expectedIncrement) { 206 // throw new AssertionError("Authenticator #2 called " + count(count) 207 // + " expected it to be called " + expected(expectedIncrement)); 208 // } 209 // count = AUTHENTICATOR.count.get(); 210 // if (count != defaultCount + 2 * expectedIncrement) { 211 // throw new AssertionError("Default Authenticator called " + count(count) 212 // + " expected it to be called " 213 // + expected(defaultCount + 2 * expectedIncrement)); 214 // } 215 216 // Now tries to set an authenticator on a connected connection. 217 URL url = url(protocol, server.getAddress(), "/"); 218 Proxy proxy = proxy(server, mode); 219 HttpURLConnection conn = openConnection(url, mode, proxy); 220 try { 221 conn.setAuthenticator(null); 222 throw new RuntimeException("Expected NullPointerException" 223 + " trying to set a null authenticator" 224 + " not raised."); 225 } catch (NullPointerException npe) { 226 System.out.println("Client: caught expected NPE" 227 + " trying to set a null authenticator: " 228 + npe); 229 } 230 conn.connect(); 231 try { 232 try { 233 conn.setAuthenticator(authOne); 234 throw new RuntimeException("Expected IllegalStateException" 235 + " trying to set an authenticator after connect" 236 + " not raised."); 237 } catch (IllegalStateException ise) { 238 System.out.println("Client: caught expected ISE" 239 + " trying to set an authenticator after connect: " 240 + ise); 241 } 242 // Uncomment the code below when 8169068 is available. 243 // try { 244 // conn.setAuthenticator(Authenticator.getDefault()); 245 // throw new RuntimeException("Expected IllegalStateException" 246 // + " trying to set an authenticator after connect" 247 // + " not raised."); 248 // } catch (IllegalStateException ise) { 249 // System.out.println("Client: caught expected ISE" 250 // + " trying to set an authenticator after connect: " 251 // + ise); 252 // } 253 try { 254 conn.setAuthenticator(null); 255 throw new RuntimeException("Expected" 256 + " IllegalStateException or NullPointerException" 257 + " trying to set a null authenticator after connect" 258 + " not raised."); 259 } catch (IllegalStateException | NullPointerException xxe) { 260 System.out.println("Client: caught expected " 261 + xxe.getClass().getSimpleName() 262 + " trying to set a null authenticator after connect: " 263 + xxe); 264 } 265 } finally { 266 conn.disconnect(); 267 } 268 269 // double check that authOne and authTwo haven't been invoked. 270 count = authOne.count.get(); 271 if (count != expectedIncrement) { 272 throw new AssertionError("Authenticator #1 called " + count(count) 273 + " expected it to be called " + expected(expectedIncrement)); 274 } 275 count = authTwo.count.get(); 276 if (count != expectedIncrement) { 277 throw new AssertionError("Authenticator #2 called " + count(count) 278 + " expected it to be called " + expected(expectedIncrement)); 279 } 280 281 // All good! 282 // return the number of times the default authenticator is supposed 283 // to have been called. 284 return scheme == HttpSchemeType.NONE ? 0 : 1 * EXPECTED_AUTH_CALLS_PER_TEST; 285 } 286 287 static String toString(Authenticator a) { 288 return sun.net.www.protocol.http.AuthenticatorKeys.getKey(a); 289 } 290 291 }