|
1 <!DOCTYPE HTML> |
|
2 <html> |
|
3 <head> |
|
4 <title>Test for Async Auth Prompt</title> |
|
5 <script type="text/javascript" src="/MochiKit/MochiKit.js"></script> |
|
6 <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> |
|
7 <script type="text/javascript" src="prompt_common.js"></script> |
|
8 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> |
|
9 |
|
10 <script class="testbody" type="text/javascript"> |
|
11 SimpleTest.waitForExplicitFinish(); |
|
12 |
|
13 // Class monitoring number of open dialog windows |
|
14 // It checks there is always open just a single dialog per application |
|
15 function dialogMonitor() { |
|
16 var observerService = SpecialPowers.Cc["@mozilla.org/observer-service;1"] |
|
17 .getService(Ci.nsIObserverService); |
|
18 observerService.addObserver(this, "domwindowopened", false); |
|
19 observerService.addObserver(this, "domwindowclosed", false); |
|
20 } |
|
21 |
|
22 /* |
|
23 * As documented in Bug 718543, checking equality of objects pulled |
|
24 * from SpecialPowers-wrapped objects is unreliable. Because of that, |
|
25 * `dialogMonitor` now tracks the number of open windows rather than |
|
26 * specific window objects. |
|
27 * |
|
28 * NB: Because the constructor (above) adds |this| directly as an observer, |
|
29 * we need to do SpecialPowers.wrapCallbackObject directly on the prototype. |
|
30 */ |
|
31 dialogMonitor.prototype = SpecialPowers.wrapCallbackObject({ |
|
32 windowsOpen : 0, |
|
33 windowsRegistered : 0, |
|
34 |
|
35 QueryInterface : function (iid) { |
|
36 const interfaces = [Ci.nsIObserver, Ci.nsISupports]; |
|
37 |
|
38 if (!interfaces.some( function(v) { return iid.equals(v) } )) |
|
39 throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE; |
|
40 return this; |
|
41 }, |
|
42 |
|
43 observe: function(subject, topic, data) { |
|
44 if (topic === "domwindowopened") { |
|
45 this.windowsOpen++; |
|
46 this.windowsRegistered++; |
|
47 return; |
|
48 } |
|
49 if (topic === "domwindowclosed") { |
|
50 this.windowsOpen--; |
|
51 return; |
|
52 } |
|
53 }, |
|
54 |
|
55 shutdown: function() { |
|
56 var observerService = SpecialPowers.Cc["@mozilla.org/observer-service;1"] |
|
57 .getService(Ci.nsIObserverService); |
|
58 observerService.removeObserver(this, "domwindowopened"); |
|
59 observerService.removeObserver(this, "domwindowclosed"); |
|
60 }, |
|
61 |
|
62 reset: function() { |
|
63 this.windowsOpen = 0; |
|
64 this.windowsRegistered = 0; |
|
65 } |
|
66 }); |
|
67 |
|
68 var monitor = new dialogMonitor(); |
|
69 |
|
70 var pwmgr, logins = []; |
|
71 |
|
72 function initLogins(pi) { |
|
73 pwmgr = SpecialPowers.Cc["@mozilla.org/login-manager;1"] |
|
74 .getService(Ci.nsILoginManager); |
|
75 |
|
76 function addLogin(host, realm, user, pass) { |
|
77 var login = SpecialPowers.Cc["@mozilla.org/login-manager/loginInfo;1"] |
|
78 .createInstance(Ci.nsILoginInfo); |
|
79 login.init(host, null, realm, user, pass, "", ""); |
|
80 pwmgr.addLogin(login); |
|
81 logins.push(login); |
|
82 } |
|
83 |
|
84 var mozproxy = "moz-proxy://" + |
|
85 SpecialPowers.wrap(pi).host + ":" + |
|
86 SpecialPowers.wrap(pi).port; |
|
87 |
|
88 addLogin(mozproxy, "proxy_realm", |
|
89 "proxy_user", "proxy_pass"); |
|
90 addLogin(mozproxy, "proxy_realm2", |
|
91 "proxy_user2", "proxy_pass2"); |
|
92 addLogin(mozproxy, "proxy_realm3", |
|
93 "proxy_user3", "proxy_pass3"); |
|
94 addLogin(mozproxy, "proxy_realm4", |
|
95 "proxy_user4", "proxy_pass4"); |
|
96 addLogin(mozproxy, "proxy_realm5", |
|
97 "proxy_user5", "proxy_pass5"); |
|
98 addLogin("http://example.com", "mochirealm", |
|
99 "user1name", "user1pass"); |
|
100 addLogin("http://example.org", "mochirealm2", |
|
101 "user2name", "user2pass"); |
|
102 addLogin("http://example.com", "mochirealm3", |
|
103 "user3name", "user3pass"); |
|
104 addLogin("http://example.com", "mochirealm4", |
|
105 "user4name", "user4pass"); |
|
106 addLogin("http://example.com", "mochirealm5", |
|
107 "user5name", "user5pass"); |
|
108 addLogin("http://example.com", "mochirealm6", |
|
109 "user6name", "user6pass"); |
|
110 } |
|
111 |
|
112 function finishTest() { |
|
113 ok(true, "finishTest removing testing logins..."); |
|
114 for (i in logins) |
|
115 pwmgr.removeLogin(logins[i]); |
|
116 |
|
117 var authMgr = SpecialPowers.Cc['@mozilla.org/network/http-auth-manager;1'] |
|
118 .getService(Ci.nsIHttpAuthManager); |
|
119 authMgr.clearAll(); |
|
120 |
|
121 monitor.shutdown(); |
|
122 SimpleTest.finish(); |
|
123 } |
|
124 |
|
125 var resolveCallback = SpecialPowers.wrapCallbackObject({ |
|
126 QueryInterface : function (iid) { |
|
127 const interfaces = [Ci.nsIProtocolProxyCallback, Ci.nsISupports]; |
|
128 |
|
129 if (!interfaces.some( function(v) { return iid.equals(v) } )) |
|
130 throw SpecialPowers.Cr.NS_ERROR_NO_INTERFACE; |
|
131 return this; |
|
132 }, |
|
133 |
|
134 onProxyAvailable : function (req, uri, pi, status) { |
|
135 initLogins(pi); |
|
136 doTest(testNum); |
|
137 } |
|
138 }); |
|
139 |
|
140 function startup() { |
|
141 //need to allow for arbitrary network servers defined in PAC instead of a hardcoded moz-proxy. |
|
142 var ios = SpecialPowers.Cc["@mozilla.org/network/io-service;1"] |
|
143 .getService(SpecialPowers.Ci.nsIIOService); |
|
144 |
|
145 var pps = SpecialPowers.Cc["@mozilla.org/network/protocol-proxy-service;1"] |
|
146 .getService(); |
|
147 |
|
148 var uri = ios.newURI("http://example.com", null, null); |
|
149 pps.asyncResolve(uri, 0, resolveCallback); |
|
150 } |
|
151 |
|
152 // --------------- Test loop spin ---------------- |
|
153 var testNum = 1; |
|
154 var iframe1; |
|
155 var iframe2a; |
|
156 var iframe2b; |
|
157 window.onload = function () { |
|
158 iframe1 = document.getElementById("iframe1"); |
|
159 iframe2a = document.getElementById("iframe2a"); |
|
160 iframe2b = document.getElementById("iframe2b"); |
|
161 iframe1.onload = onFrameLoad; |
|
162 iframe2a.onload = onFrameLoad; |
|
163 iframe2b.onload = onFrameLoad; |
|
164 |
|
165 startup(); |
|
166 } |
|
167 |
|
168 var expectedLoads; |
|
169 var expectedDialogs; |
|
170 function onFrameLoad() |
|
171 { |
|
172 if (--expectedLoads == 0) { |
|
173 // All pages expected to load has loaded, continue with the next test |
|
174 ok(true, "Expected frames loaded"); |
|
175 |
|
176 doCheck(testNum); |
|
177 monitor.reset(); |
|
178 |
|
179 testNum++; |
|
180 doTest(testNum); |
|
181 } |
|
182 } |
|
183 |
|
184 function doTest(testNum) |
|
185 { |
|
186 /* |
|
187 * These contentDocument variables are located here, |
|
188 * rather than in the global scope, because SpecialPowers threw |
|
189 * errors (complaining that the objects were deleted) |
|
190 * when these were in the global scope. |
|
191 */ |
|
192 var iframe1Doc = SpecialPowers.wrap(iframe1).contentDocument; |
|
193 var iframe2aDoc = SpecialPowers.wrap(iframe2a).contentDocument; |
|
194 var iframe2bDoc = SpecialPowers.wrap(iframe2b).contentDocument; |
|
195 var exampleCom = "http://example.com/tests/toolkit/components/passwordmgr/test/"; |
|
196 var exampleOrg = "http://example.org/tests/toolkit/components/passwordmgr/test/"; |
|
197 |
|
198 switch (testNum) |
|
199 { |
|
200 case 1: |
|
201 // Load through a single proxy with authentication required 3 different |
|
202 // pages, first with one login, other two with their own different login. |
|
203 // We expect to show just a single dialog for proxy authentication and |
|
204 // then two dialogs to authenticate to login 1 and then login 2. |
|
205 ok(true, "doTest testNum 1"); |
|
206 expectedLoads = 3; |
|
207 expectedDialogs = 3; |
|
208 iframe1.src = exampleCom + "authenticate.sjs?"+ |
|
209 "r=1&"+ |
|
210 "user=user1name&"+ |
|
211 "pass=user1pass&"+ |
|
212 "realm=mochirealm&"+ |
|
213 "proxy_user=proxy_user&"+ |
|
214 "proxy_pass=proxy_pass&"+ |
|
215 "proxy_realm=proxy_realm"; |
|
216 iframe2a.src = exampleOrg + "authenticate.sjs?"+ |
|
217 "r=2&"+ |
|
218 "user=user2name&"+ |
|
219 "pass=user2pass&"+ |
|
220 "realm=mochirealm2&"+ |
|
221 "proxy_user=proxy_user&"+ |
|
222 "proxy_pass=proxy_pass&"+ |
|
223 "proxy_realm=proxy_realm"; |
|
224 iframe2b.src = exampleOrg + "authenticate.sjs?"+ |
|
225 "r=3&"+ |
|
226 "user=user2name&"+ |
|
227 "pass=user2pass&"+ |
|
228 "realm=mochirealm2&"+ |
|
229 "proxy_user=proxy_user&"+ |
|
230 "proxy_pass=proxy_pass&"+ |
|
231 "proxy_realm=proxy_realm"; |
|
232 break; |
|
233 |
|
234 case 2: |
|
235 // Load an iframe with 3 subpages all requiring the same login through |
|
236 // anuthenticated proxy. We expect 2 dialogs, proxy authentication |
|
237 // and web authentication. |
|
238 ok(true, "doTest testNum 2"); |
|
239 expectedLoads = 3; |
|
240 expectedDialogs = 2; |
|
241 iframe1.src = exampleCom + "subtst_prompt_async.html"; |
|
242 iframe2a.src = "about:blank"; |
|
243 iframe2b.src = "about:blank"; |
|
244 break; |
|
245 |
|
246 case 3: |
|
247 // Load in the iframe page through unauthenticated proxy |
|
248 // and discard the proxy authentication. We expect to see |
|
249 // unauthenticated page content and just a single dialog. |
|
250 ok(true, "doTest testNum 3"); |
|
251 expectedLoads = 1; |
|
252 expectedDialogs = 1; |
|
253 iframe1.src = exampleCom + "authenticate.sjs?"+ |
|
254 "user=user4name&"+ |
|
255 "pass=user4pass&"+ |
|
256 "realm=mochirealm4&"+ |
|
257 "proxy_user=proxy_user3&"+ |
|
258 "proxy_pass=proxy_pass3&"+ |
|
259 "proxy_realm=proxy_realm3"; |
|
260 break; |
|
261 |
|
262 case 4: |
|
263 // Reload the frame from previous step and pass the proxy authentication |
|
264 // but cancel the WWW authentication. We should get the proxy=ok and WWW=fail |
|
265 // content as a result. |
|
266 ok(true, "doTest testNum 4"); |
|
267 expectedLoads = 1; |
|
268 expectedDialogs = 2; |
|
269 iframe1.src = exampleCom + "authenticate.sjs?"+ |
|
270 "user=user4name&"+ |
|
271 "pass=user4pass&"+ |
|
272 "realm=mochirealm4&"+ |
|
273 "proxy_user=proxy_user3&"+ |
|
274 "proxy_pass=proxy_pass3&"+ |
|
275 "proxy_realm=proxy_realm3"; |
|
276 |
|
277 |
|
278 break; |
|
279 |
|
280 case 5: |
|
281 // Same as the previous two steps but let the server generate |
|
282 // huge content load to check http channel is capable to handle |
|
283 // case when auth dialog is canceled or accepted before unauthenticated |
|
284 // content data is load from the server. (This would be better to |
|
285 // implement using delay of server response). |
|
286 ok(true, "doTest testNum 5"); |
|
287 expectedLoads = 1; |
|
288 expectedDialogs = 1; |
|
289 iframe1.src = exampleCom + "authenticate.sjs?"+ |
|
290 "user=user5name&"+ |
|
291 "pass=user5pass&"+ |
|
292 "realm=mochirealm5&"+ |
|
293 "proxy_user=proxy_user4&"+ |
|
294 "proxy_pass=proxy_pass4&"+ |
|
295 "proxy_realm=proxy_realm4&"+ |
|
296 "huge=1"; |
|
297 break; |
|
298 |
|
299 case 6: |
|
300 // Reload the frame from the previous step and let the proxy |
|
301 // authentication pass but WWW fail. We expect two dialogs |
|
302 // and an unathenticated page content load. |
|
303 ok(true, "doTest testNum 6"); |
|
304 expectedLoads = 1; |
|
305 expectedDialogs = 2; |
|
306 iframe1.src = exampleCom + "authenticate.sjs?"+ |
|
307 "user=user5name&"+ |
|
308 "pass=user5pass&"+ |
|
309 "realm=mochirealm5&"+ |
|
310 "proxy_user=proxy_user4&"+ |
|
311 "proxy_pass=proxy_pass4&"+ |
|
312 "proxy_realm=proxy_realm4&"+ |
|
313 "huge=1"; |
|
314 break; |
|
315 |
|
316 case 7: |
|
317 // Reload again and let pass all authentication dialogs. |
|
318 // Check we get the authenticated content not broken by |
|
319 // the unauthenticated content. |
|
320 ok(true, "doTest testNum 7"); |
|
321 expectedLoads = 1; |
|
322 expectedDialogs = 1; |
|
323 iframe1Doc.location.reload(); |
|
324 break; |
|
325 |
|
326 case 8: |
|
327 // Check we proccess all challenges sent by server when |
|
328 // user cancels prompts |
|
329 ok(true, "doTest testNum 8"); |
|
330 expectedLoads = 1; |
|
331 expectedDialogs = 5; |
|
332 iframe1.src = exampleCom + "authenticate.sjs?"+ |
|
333 "user=user6name&"+ |
|
334 "pass=user6pass&"+ |
|
335 "realm=mochirealm6&"+ |
|
336 "proxy_user=proxy_user5&"+ |
|
337 "proxy_pass=proxy_pass5&"+ |
|
338 "proxy_realm=proxy_realm5&"+ |
|
339 "huge=1&"+ |
|
340 "multiple=3"; |
|
341 break; |
|
342 |
|
343 case 9: |
|
344 finishTest(); |
|
345 return; |
|
346 } |
|
347 |
|
348 startCallbackTimer(); |
|
349 } |
|
350 |
|
351 function handleDialog(doc, testNum) |
|
352 { |
|
353 var dialog = doc.getElementById("commonDialog"); |
|
354 |
|
355 switch (testNum) |
|
356 { |
|
357 case 1: |
|
358 case 2: |
|
359 dialog.acceptDialog(); |
|
360 break; |
|
361 |
|
362 case 3: |
|
363 dialog.cancelDialog(); |
|
364 setTimeout(onFrameLoad, 10); // there are no successful frames for test 3 |
|
365 break; |
|
366 |
|
367 case 4: |
|
368 if (expectedDialogs == 2) |
|
369 dialog.acceptDialog(); |
|
370 else |
|
371 dialog.cancelDialog(); |
|
372 break; |
|
373 |
|
374 case 5: |
|
375 dialog.cancelDialog(); |
|
376 setTimeout(onFrameLoad, 10); // there are no successful frames for test 5 |
|
377 break; |
|
378 |
|
379 case 6: |
|
380 if (expectedDialogs == 2) |
|
381 dialog.acceptDialog(); |
|
382 else |
|
383 dialog.cancelDialog(); |
|
384 break; |
|
385 |
|
386 case 7: |
|
387 dialog.acceptDialog(); |
|
388 break; |
|
389 |
|
390 case 8: |
|
391 if (expectedDialogs == 3 || expectedDialogs == 1) |
|
392 dialog.acceptDialog(); |
|
393 else |
|
394 dialog.cancelDialog(); |
|
395 break; |
|
396 |
|
397 default: |
|
398 ok(false, "Unhandled testNum "+testNum+" in handleDialog"); |
|
399 } |
|
400 |
|
401 if (--expectedDialogs > 0) |
|
402 startCallbackTimer(); |
|
403 } |
|
404 |
|
405 function doCheck(testNum) |
|
406 { |
|
407 var iframe1Doc = SpecialPowers.wrap(iframe1).contentDocument; |
|
408 var iframe2aDoc = SpecialPowers.wrap(iframe2a).contentDocument; |
|
409 var iframe2bDoc = SpecialPowers.wrap(iframe2b).contentDocument; |
|
410 switch (testNum) |
|
411 { |
|
412 case 1: |
|
413 ok(true, "doCheck testNum 1"); |
|
414 is(monitor.windowsRegistered, 3, "Registered 3 open dialogs"); |
|
415 |
|
416 var authok1 = iframe1Doc.getElementById("ok").textContent; |
|
417 var proxyok1 = iframe1Doc.getElementById("proxy").textContent; |
|
418 |
|
419 var authok2a = iframe2aDoc.getElementById("ok").textContent; |
|
420 var proxyok2a = iframe2aDoc.getElementById("proxy").textContent; |
|
421 |
|
422 var authok2b = iframe2bDoc.getElementById("ok").textContent; |
|
423 var proxyok2b = iframe2bDoc.getElementById("proxy").textContent; |
|
424 |
|
425 is(authok1, "PASS", "WWW Authorization OK, frame1"); |
|
426 is(authok2a, "PASS", "WWW Authorization OK, frame2a"); |
|
427 is(authok2b, "PASS", "WWW Authorization OK, frame2b"); |
|
428 is(proxyok1, "PASS", "Proxy Authorization OK, frame1"); |
|
429 is(proxyok2a, "PASS", "Proxy Authorization OK, frame2a"); |
|
430 is(proxyok2b, "PASS", "Proxy Authorization OK, frame2b"); |
|
431 break; |
|
432 |
|
433 case 2: |
|
434 is(monitor.windowsRegistered, 2, "Registered 2 open dialogs"); |
|
435 ok(true, "doCheck testNum 2"); |
|
436 |
|
437 function checkIframe(frame) { |
|
438 var doc = SpecialPowers.wrap(frame).contentDocument; |
|
439 |
|
440 var authok = doc.getElementById("ok").textContent; |
|
441 var proxyok = doc.getElementById("proxy").textContent; |
|
442 |
|
443 is(authok, "PASS", "WWW Authorization OK, " + frame.id); |
|
444 is(proxyok, "PASS", "Proxy Authorization OK, " + frame.id); |
|
445 } |
|
446 |
|
447 checkIframe(iframe1Doc.getElementById("iframe1")); |
|
448 checkIframe(iframe1Doc.getElementById("iframe2")); |
|
449 checkIframe(iframe1Doc.getElementById("iframe3")); |
|
450 break; |
|
451 |
|
452 case 3: |
|
453 ok(true, "doCheck testNum 3"); |
|
454 is(monitor.windowsRegistered, 1, "Registered 1 open dialog"); |
|
455 |
|
456 // ensure that the page content is not displayed on failed proxy auth |
|
457 is(iframe1Doc.getElementById("ok"), undefined, "frame did not load"); |
|
458 break; |
|
459 |
|
460 case 4: |
|
461 ok(true, "doCheck testNum 4"); |
|
462 is(monitor.windowsRegistered, 2, "Registered 2 open dialogs"); |
|
463 var authok1 = iframe1Doc.getElementById("ok").textContent; |
|
464 var proxyok1 = iframe1Doc.getElementById("proxy").textContent; |
|
465 |
|
466 is(authok1, "FAIL", "WWW Authorization FAILED, frame1"); |
|
467 is(proxyok1, "PASS", "Proxy Authorization OK, frame1"); |
|
468 break; |
|
469 |
|
470 case 5: |
|
471 ok(true, "doCheck testNum 5"); |
|
472 is(monitor.windowsRegistered, 1, "Registered 1 open dialog"); |
|
473 |
|
474 // ensure that the page content is not displayed on failed proxy auth |
|
475 is(iframe1Doc.getElementById("footnote"), undefined, "frame did not load"); |
|
476 break; |
|
477 |
|
478 case 6: |
|
479 ok(true, "doCheck testNum 6"); |
|
480 is(monitor.windowsRegistered, 2, "Registered 2 open dialogs"); |
|
481 var authok1 = iframe1Doc.getElementById("ok").textContent; |
|
482 var proxyok1 = iframe1Doc.getElementById("proxy").textContent; |
|
483 var footnote = iframe1Doc.getElementById("footnote").textContent; |
|
484 |
|
485 is(authok1, "FAIL", "WWW Authorization FAILED, frame1"); |
|
486 is(proxyok1, "PASS", "Proxy Authorization OK, frame1"); |
|
487 is(footnote, "This is a footnote after the huge content fill", |
|
488 "Footnote present and loaded completely"); |
|
489 break; |
|
490 |
|
491 case 7: |
|
492 ok(true, "doCheck testNum 7"); |
|
493 is(monitor.windowsRegistered, 1, "Registered 1 open dialogs"); |
|
494 var authok1 = iframe1Doc.getElementById("ok").textContent; |
|
495 var proxyok1 = iframe1Doc.getElementById("proxy").textContent; |
|
496 var footnote = iframe1Doc.getElementById("footnote").textContent; |
|
497 |
|
498 is(authok1, "PASS", "WWW Authorization OK, frame1"); |
|
499 is(proxyok1, "PASS", "Proxy Authorization OK, frame1"); |
|
500 is(footnote, "This is a footnote after the huge content fill", |
|
501 "Footnote present and loaded completely"); |
|
502 break; |
|
503 |
|
504 case 8: |
|
505 ok(true, "doCheck testNum 8"); |
|
506 is(monitor.windowsRegistered, 5, "Registered 5 open dialogs"); |
|
507 var authok1 = iframe1Doc.getElementById("ok").textContent; |
|
508 var proxyok1 = iframe1Doc.getElementById("proxy").textContent; |
|
509 var footnote = iframe1Doc.getElementById("footnote").textContent; |
|
510 |
|
511 is(authok1, "PASS", "WWW Authorization OK, frame1"); |
|
512 is(proxyok1, "PASS", "Proxy Authorization OK, frame1"); |
|
513 is(footnote, "This is a footnote after the huge content fill", |
|
514 "Footnote present and loaded completely"); |
|
515 break; |
|
516 |
|
517 default: |
|
518 ok(false, "Unhandled testNum "+testNum+" in doCheck"); |
|
519 } |
|
520 } |
|
521 |
|
522 </script> |
|
523 </head> |
|
524 <body> |
|
525 <iframe id="iframe1"></iframe> |
|
526 <iframe id="iframe2a"></iframe> |
|
527 <iframe id="iframe2b"></iframe> |
|
528 </body> |
|
529 </html> |