1 /* 2 * Copyright (c) 2002, 2010, 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 4769350 27 * @library ../../../sun/net/www/httptest/ 28 * @build HttpCallback TestHttpServer ClosedChannelList HttpTransaction AbstractCallback 29 * @run main/othervm B4769350 server 30 * @run main/othervm B4769350 proxy 31 * @summary proxy authentication username and password caching only works in serial case 32 * Run in othervm since the test sets system properties that are read by the 33 * networking stack and cached when the HTTP handler is invoked, and previous 34 * tests may already have invoked the HTTP handler. 35 */ 36 37 import java.io.*; 38 import java.net.*; 39 40 public class B4769350 { 41 42 static int count = 0; 43 static boolean error = false; 44 45 static void read (InputStream is) throws IOException { 46 int c; 47 while ((c=is.read()) != -1) { 48 //System.out.write (c); 49 } 50 } 51 52 static class Client extends Thread { 53 String authority, path; 54 boolean allowerror; 55 56 Client (String authority, String path, boolean allowerror) { 57 super("Thread-" + path); 58 this.authority = authority; 59 this.path = path; 60 this.allowerror = allowerror; 61 } 62 63 public void run () { 64 try { 65 URI u = new URI ("http", authority, path, null, null); 66 URL url = u.toURL(); 67 URLConnection urlc = url.openConnection (); 68 InputStream is = urlc.getInputStream (); 69 read (is); 70 is.close(); 71 } catch (URISyntaxException e) { 72 System.out.println (e); 73 error = true; 74 } catch (IOException e) { 75 if (!allowerror) { 76 System.out.println (Thread.currentThread().getName() + " " + e); 77 e.printStackTrace(); 78 error = true; 79 } 80 } 81 } 82 } 83 84 static class CallBack extends AbstractCallback { 85 86 void errorReply (HttpTransaction req, String reply) throws IOException { 87 req.addResponseHeader ("Connection", "close"); 88 req.addResponseHeader ("WWW-Authenticate", reply); 89 req.sendResponse (401, "Unauthorized"); 90 req.orderlyClose(); 91 } 92 93 void proxyReply (HttpTransaction req, String reply) throws IOException { 94 req.addResponseHeader ("Proxy-Authenticate", reply); 95 req.sendResponse (407, "Proxy Authentication Required"); 96 } 97 98 void okReply (HttpTransaction req) throws IOException { 99 req.addResponseHeader ("Connection", "close"); 100 req.setResponseEntityBody ("Hello ."); 101 req.sendResponse (200, "Ok"); 102 req.orderlyClose(); 103 } 104 105 public void request (HttpTransaction req, int count) { 106 try { 107 URI uri = req.getRequestURI(); 108 String path = uri.getPath(); 109 if (path.endsWith ("/t1a")) { 110 doT1a (req, count); 111 } else if (path.endsWith ("/t1b")) { 112 doT1b (req, count); 113 } else if (path.endsWith ("/t1c")) { 114 doT1c (req, count); 115 } else if (path.endsWith ("/t1d")) { 116 doT1d (req, count); 117 } else if (path.endsWith ("/t2a")) { 118 doT2a (req, count); 119 } else if (path.endsWith ("/t2b")) { 120 doT2b (req, count); 121 } else if (path.endsWith ("/t3a")) { 122 doT3a (req, count); 123 } else if (path.endsWith ("/t3b")) { 124 doT3bc (req, count); 125 } else if (path.endsWith ("/t3c")) { 126 doT3bc (req, count); 127 } else { 128 System.out.println ("unexpected request URI"); 129 } 130 } catch (IOException e) { 131 e.printStackTrace(); 132 } 133 } 134 135 /* T1 tests the client by sending 4 requests to 2 different realms 136 * in parallel. The client should recognise two pairs of dependent requests 137 * and execute the first of each pair in parallel. When they both succeed 138 * the second requests should be executed without calling the authenticator. 139 * The test succeeds if the authenticator was only called twice. 140 */ 141 void doT1a (HttpTransaction req, int count) throws IOException { 142 switch (count) { 143 case 0: 144 errorReply (req, "Basic realm=\"realm1\""); 145 TestHttpServer.rendezvous ("one", 2); 146 break; 147 case 1: 148 TestHttpServer.waitForCondition ("cond2"); 149 okReply (req); 150 break; 151 default: 152 System.out.println ("Unexpected request"); 153 } 154 } 155 156 157 void doT1b (HttpTransaction req, int count) throws IOException { 158 switch (count) { 159 case 0: 160 errorReply (req, "Basic realm=\"realm2\""); 161 TestHttpServer.rendezvous ("one", 2); 162 TestHttpServer.setCondition ("cond1"); 163 break; 164 case 1: 165 TestHttpServer.waitForCondition ("cond2"); 166 okReply (req); 167 break; 168 default: 169 System.out.println ("Unexpected request"); 170 } 171 } 172 173 void doT1c (HttpTransaction req, int count) throws IOException { 174 switch (count) { 175 case 0: 176 errorReply (req, "Basic realm=\"realm1\""); 177 TestHttpServer.rendezvous ("two", 2); 178 break; 179 case 1: 180 okReply (req); 181 break; 182 default: 183 System.out.println ("Unexpected request"); 184 } 185 } 186 187 void doT1d (HttpTransaction req, int count) throws IOException { 188 switch (count) { 189 case 0: 190 errorReply (req, "Basic realm=\"realm2\""); 191 TestHttpServer.rendezvous ("two", 2); 192 TestHttpServer.setCondition ("cond2"); 193 break; 194 case 1: 195 okReply (req); 196 break; 197 default: 198 System.out.println ("Unexpected request"); 199 } 200 } 201 202 203 /* T2 tests to check that if initial authentication fails, the second will 204 * succeed, and the authenticator is called twice 205 */ 206 207 void doT2a (HttpTransaction req, int count) throws IOException { 208 /* This will be called several times */ 209 if (count == 1) { 210 TestHttpServer.setCondition ("T2cond1"); 211 } 212 errorReply (req, "Basic realm=\"realm3\""); 213 } 214 215 void doT2b (HttpTransaction req, int count) throws IOException { 216 switch (count) { 217 case 0: 218 errorReply (req, "Basic realm=\"realm3\""); 219 break; 220 case 1: 221 okReply (req); 222 break; 223 default: 224 System.out.println ("Unexpected request"); 225 } 226 } 227 228 /* T3 tests proxy and server authentication. three threads request same 229 * resource at same time. Authenticator should be called once for server 230 * and once for proxy 231 */ 232 void doT3a (HttpTransaction req, int count) throws IOException { 233 switch (count) { 234 case 0: 235 proxyReply (req, "Basic realm=\"proxy\""); 236 TestHttpServer.setCondition ("T3cond1"); 237 break; 238 case 1: 239 errorReply (req, "Basic realm=\"realm4\""); 240 break; 241 case 2: 242 okReply (req); 243 break; 244 default: 245 System.out.println ("Unexpected request"); 246 } 247 } 248 249 void doT3bc (HttpTransaction req, int count) throws IOException { 250 switch (count) { 251 case 0: 252 proxyReply (req, "Basic realm=\"proxy\""); 253 break; 254 case 1: 255 okReply (req); 256 break; 257 default: 258 System.out.println ("Unexpected request"); 259 } 260 } 261 }; 262 263 static TestHttpServer server; 264 static MyAuthenticator auth = new MyAuthenticator (); 265 266 static int redirects = 4; 267 268 static Client c1,c2,c3,c4,c5,c6,c7,c8,c9; 269 270 static void doServerTests (String authority) throws Exception { 271 System.out.println ("Doing Server tests"); 272 System.out.println ("T1"); 273 c1 = new Client (authority, "/test/realm1/t1a", false); 274 c2 = new Client (authority, "/test/realm2/t1b", false); 275 c3 = new Client (authority, "/test/realm1/t1c", false); 276 c4 = new Client (authority, "/test/realm2/t1d", false); 277 278 c1.start(); c2.start(); 279 TestHttpServer.waitForCondition ("cond1"); 280 c3.start(); c4.start(); 281 c1.join(); c2.join(); c3.join(); c4.join(); 282 283 int f = auth.getCount(); 284 if (f != 2) { 285 except ("Authenticator was called "+f+" times. Should be 2"); 286 } 287 if (error) { 288 except ("error occurred"); 289 } 290 291 auth.resetCount(); 292 System.out.println ("T2"); 293 294 c5 = new Client (authority, "/test/realm3/t2a", true); 295 c6 = new Client (authority, "/test/realm3/t2b", false); 296 c5.start (); 297 TestHttpServer.waitForCondition ("T2cond1"); 298 c6.start (); 299 c5.join(); c6.join(); 300 301 f = auth.getCount(); 302 if (f != redirects+1) { 303 except ("Authenticator was called "+f+" times. Should be: " + redirects+1); 304 } 305 if (error) { 306 except ("error occurred"); 307 } 308 } 309 310 static void doProxyTests (String authority) throws Exception { 311 System.out.println ("Doing Proxy tests"); 312 c7 = new Client (authority, "/test/realm4/t3a", false); 313 c8 = new Client (authority, "/test/realm4/t3b", false); 314 c9 = new Client (authority, "/test/realm4/t3c", false); 315 c7.start (); 316 TestHttpServer.waitForCondition ("T3cond1"); 317 c8.start (); 318 c9.start (); 319 c7.join(); c8.join(); c9.join(); 320 321 int f = auth.getCount(); 322 if (f != 2) { 323 except ("Authenticator was called "+f+" times. Should be: " + 2); 324 } 325 if (error) { 326 except ("error occurred"); 327 } 328 } 329 330 public static void main (String[] args) throws Exception { 331 System.setProperty ("http.maxRedirects", Integer.toString (redirects)); 332 System.setProperty ("http.auth.serializeRequests", "true"); 333 Authenticator.setDefault (auth); 334 boolean proxy = args[0].equals ("proxy"); 335 try { 336 server = new TestHttpServer (new CallBack(), 10, 1, 0); 337 System.out.println ("Server: listening on port: " + server.getLocalPort()); 338 if (proxy) { 339 System.setProperty ("http.proxyHost", "localhost"); 340 System.setProperty ("http.proxyPort",Integer.toString(server.getLocalPort())); 341 doProxyTests ("www.foo.com"); 342 } else { 343 doServerTests ("localhost:"+server.getLocalPort()); 344 } 345 server.terminate(); 346 347 } catch (Exception e) { 348 if (server != null) { 349 server.terminate(); 350 } 351 throw e; 352 } 353 } 354 355 static void pause (int millis) { 356 try { 357 Thread.sleep (millis); 358 } catch (InterruptedException e) {} 359 } 360 361 public static void except (String s) { 362 server.terminate(); 363 throw new RuntimeException (s); 364 } 365 366 static class MyAuthenticator extends Authenticator { 367 MyAuthenticator () { 368 super (); 369 } 370 371 int count = 0; 372 373 public PasswordAuthentication getPasswordAuthentication () { 374 //System.out.println ("Authenticator called: " + getRequestingPrompt()); 375 //try { 376 //Thread.sleep (1000); 377 //} catch (InterruptedException e) {} 378 PasswordAuthentication pw; 379 pw = new PasswordAuthentication ("user", "pass1".toCharArray()); 380 count ++; 381 return pw; 382 } 383 384 public void resetCount () { 385 count = 0; 386 } 387 388 public int getCount () { 389 return (count); 390 } 391 } 392 }