Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / netwerk / test / unit / test_auth_proxy.js
blobd49e230922d29cbb03375b5c3c59ed4f3b629f0d
1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 /**
7 * This tests the automatic login to the proxy with password,
8 * if the password is stored and the browser is restarted.
10 * <copied from="test_authentication.js"/>
13 "use strict";
15 const { HttpServer } = ChromeUtils.importESModule(
16 "resource://testing-common/httpd.sys.mjs"
19 const FLAG_RETURN_FALSE = 1 << 0;
20 const FLAG_WRONG_PASSWORD = 1 << 1;
21 const FLAG_PREVIOUS_FAILED = 1 << 2;
23 function AuthPrompt2(proxyFlags, hostFlags) {
24 this.proxyCred.flags = proxyFlags;
25 this.hostCred.flags = hostFlags;
27 AuthPrompt2.prototype = {
28 proxyCred: {
29 user: "proxy",
30 pass: "guest",
31 realmExpected: "intern",
32 flags: 0,
34 hostCred: { user: "host", pass: "guest", realmExpected: "extern", flags: 0 },
36 QueryInterface: ChromeUtils.generateQI(["nsIAuthPrompt2"]),
38 promptAuth: function ap2_promptAuth(channel, encryptionLevel, authInfo) {
39 try {
40 // never HOST and PROXY set at the same time in prompt
41 Assert.equal(
42 (authInfo.flags & Ci.nsIAuthInformation.AUTH_HOST) != 0,
43 (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) == 0
46 var isProxy = (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) != 0;
47 var cred = isProxy ? this.proxyCred : this.hostCred;
49 dump(
50 "with flags: " +
51 ((cred.flags & FLAG_WRONG_PASSWORD) != 0 ? "wrong password" : "") +
52 " " +
53 ((cred.flags & FLAG_PREVIOUS_FAILED) != 0 ? "previous failed" : "") +
54 " " +
55 ((cred.flags & FLAG_RETURN_FALSE) != 0 ? "return false" : "") +
56 "\n"
59 // PROXY properly set by necko (checked using realm)
60 Assert.equal(cred.realmExpected, authInfo.realm);
62 // PREVIOUS_FAILED properly set by necko
63 Assert.equal(
64 (cred.flags & FLAG_PREVIOUS_FAILED) != 0,
65 (authInfo.flags & Ci.nsIAuthInformation.PREVIOUS_FAILED) != 0
68 if (cred.flags & FLAG_RETURN_FALSE) {
69 cred.flags |= FLAG_PREVIOUS_FAILED;
70 cred.flags &= ~FLAG_RETURN_FALSE;
71 return false;
74 authInfo.username = cred.user;
75 if (cred.flags & FLAG_WRONG_PASSWORD) {
76 authInfo.password = cred.pass + ".wrong";
77 cred.flags |= FLAG_PREVIOUS_FAILED;
78 // Now clear the flag to avoid an infinite loop
79 cred.flags &= ~FLAG_WRONG_PASSWORD;
80 } else {
81 authInfo.password = cred.pass;
82 cred.flags &= ~FLAG_PREVIOUS_FAILED;
84 } catch (e) {
85 do_throw(e);
87 return true;
90 asyncPromptAuth: function ap2_async(
91 channel,
92 callback,
93 context,
94 encryptionLevel,
95 authInfo
96 ) {
97 var me = this;
98 var allOverAndDead = false;
99 executeSoon(function () {
100 try {
101 if (allOverAndDead) {
102 throw new Error("already canceled");
104 var ret = me.promptAuth(channel, encryptionLevel, authInfo);
105 if (!ret) {
106 callback.onAuthCancelled(context, true);
107 } else {
108 callback.onAuthAvailable(context, authInfo);
110 allOverAndDead = true;
111 } catch (e) {
112 do_throw(e);
115 return new Cancelable(function () {
116 if (allOverAndDead) {
117 throw new Error("can't cancel, already ran");
119 callback.onAuthAvailable(context, authInfo);
120 allOverAndDead = true;
125 function Cancelable(onCancelFunc) {
126 this.onCancelFunc = onCancelFunc;
128 Cancelable.prototype = {
129 QueryInterface: ChromeUtils.generateQI(["nsICancelable"]),
130 cancel: function cancel() {
131 try {
132 this.onCancelFunc();
133 } catch (e) {
134 do_throw(e);
139 function Requestor(proxyFlags, hostFlags) {
140 this.proxyFlags = proxyFlags;
141 this.hostFlags = hostFlags;
143 Requestor.prototype = {
144 QueryInterface: ChromeUtils.generateQI(["nsIInterfaceRequestor"]),
146 getInterface: function requestor_gi(iid) {
147 if (iid.equals(Ci.nsIAuthPrompt)) {
148 dump("authprompt1 not implemented\n");
149 throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
151 if (iid.equals(Ci.nsIAuthPrompt2)) {
152 try {
153 // Allow the prompt to store state by caching it here
154 if (!this.prompt2) {
155 this.prompt2 = new AuthPrompt2(this.proxyFlags, this.hostFlags);
157 return this.prompt2;
158 } catch (e) {
159 do_throw(e);
162 throw Components.Exception("", Cr.NS_ERROR_NO_INTERFACE);
165 prompt2: null,
168 var listener = {
169 expectedCode: -1, // uninitialized
171 onStartRequest: function test_onStartR(request) {
172 try {
173 // Proxy auth cancellation return failures to avoid spoofing
174 if (
175 !Components.isSuccessCode(request.status) &&
176 this.expectedCode != 407
178 do_throw("Channel should have a success code!");
181 if (!(request instanceof Ci.nsIHttpChannel)) {
182 do_throw("Expecting an HTTP channel");
185 Assert.equal(this.expectedCode, request.responseStatus);
186 // If we expect 200, the request should have succeeded
187 Assert.equal(this.expectedCode == 200, request.requestSucceeded);
189 var cookie = "";
190 try {
191 cookie = request.getRequestHeader("Cookie");
192 } catch (e) {}
193 Assert.equal(cookie, "");
194 } catch (e) {
195 do_throw("Unexpected exception: " + e);
198 throw Components.Exception("", Cr.NS_ERROR_ABORT);
201 onDataAvailable: function test_ODA() {
202 do_throw("Should not get any data!");
205 onStopRequest: function test_onStopR(request, status) {
206 Assert.equal(status, Cr.NS_ERROR_ABORT);
208 if (current_test < tests.length - 1) {
209 // First, need to clear the auth cache
210 Cc["@mozilla.org/network/http-auth-manager;1"]
211 .getService(Ci.nsIHttpAuthManager)
212 .clearAll();
214 current_test++;
215 tests[current_test]();
216 } else {
217 do_test_pending();
218 httpserv.stop(do_test_finished);
221 do_test_finished();
225 function makeChan(url) {
226 if (!url) {
227 url = "http://somesite/";
230 return NetUtil.newChannel({
231 uri: url,
232 loadUsingSystemPrincipal: true,
233 }).QueryInterface(Ci.nsIHttpChannel);
236 var current_test = 0;
237 var httpserv = null;
239 function run_test() {
240 httpserv = new HttpServer();
241 httpserv.registerPathHandler("/", proxyAuthHandler);
242 httpserv.identity.add("http", "somesite", 80);
243 httpserv.start(-1);
245 Services.prefs.setCharPref("network.proxy.http", "localhost");
246 Services.prefs.setIntPref(
247 "network.proxy.http_port",
248 httpserv.identity.primaryPort
250 Services.prefs.setCharPref("network.proxy.no_proxies_on", "");
251 Services.prefs.setIntPref("network.proxy.type", 1);
253 // Turn off the authentication dialog blocking for this test.
254 Services.prefs.setIntPref("network.auth.subresource-http-auth-allow", 2);
255 Services.prefs.setBoolPref(
256 "network.auth.non-web-content-triggered-resources-http-auth-allow",
257 true
260 registerCleanupFunction(() => {
261 Services.prefs.clearUserPref("network.proxy.http");
262 Services.prefs.clearUserPref("network.proxy.http_port");
263 Services.prefs.clearUserPref("network.proxy.no_proxies_on");
264 Services.prefs.clearUserPref("network.proxy.type");
265 Services.prefs.clearUserPref("network.auth.subresource-http-auth-allow");
266 Services.prefs.clearUserPref(
267 "network.auth.non-web-content-triggered-resources-http-auth-allow"
271 tests[current_test]();
274 function test_proxy_returnfalse() {
275 dump("\ntest: proxy returnfalse\n");
276 var chan = makeChan();
277 chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 0);
278 listener.expectedCode = 407; // Proxy Unauthorized
279 chan.asyncOpen(listener);
281 do_test_pending();
284 function test_proxy_wrongpw() {
285 dump("\ntest: proxy wrongpw\n");
286 var chan = makeChan();
287 chan.notificationCallbacks = new Requestor(FLAG_WRONG_PASSWORD, 0);
288 listener.expectedCode = 200; // Eventually OK
289 chan.asyncOpen(listener);
290 do_test_pending();
293 function test_all_ok() {
294 dump("\ntest: all ok\n");
295 var chan = makeChan();
296 chan.notificationCallbacks = new Requestor(0, 0);
297 listener.expectedCode = 200; // OK
298 chan.asyncOpen(listener);
299 do_test_pending();
302 function test_proxy_407_cookie() {
303 var chan = makeChan();
304 chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 0);
305 chan.setRequestHeader("X-Set-407-Cookie", "1", false);
306 listener.expectedCode = 407; // Proxy Unauthorized
307 chan.asyncOpen(listener);
309 do_test_pending();
312 function test_proxy_200_cookie() {
313 var chan = makeChan();
314 chan.notificationCallbacks = new Requestor(0, 0);
315 chan.setRequestHeader("X-Set-407-Cookie", "1", false);
316 listener.expectedCode = 200; // OK
317 chan.asyncOpen(listener);
318 do_test_pending();
321 function test_host_returnfalse() {
322 dump("\ntest: host returnfalse\n");
323 var chan = makeChan();
324 chan.notificationCallbacks = new Requestor(0, FLAG_RETURN_FALSE);
325 listener.expectedCode = 401; // Host Unauthorized
326 chan.asyncOpen(listener);
328 do_test_pending();
331 function test_host_wrongpw() {
332 dump("\ntest: host wrongpw\n");
333 var chan = makeChan();
334 chan.notificationCallbacks = new Requestor(0, FLAG_WRONG_PASSWORD);
335 listener.expectedCode = 200; // Eventually OK
336 chan.asyncOpen(listener);
337 do_test_pending();
340 function test_proxy_wrongpw_host_wrongpw() {
341 dump("\ntest: proxy wrongpw, host wrongpw\n");
342 var chan = makeChan();
343 chan.notificationCallbacks = new Requestor(
344 FLAG_WRONG_PASSWORD,
345 FLAG_WRONG_PASSWORD
347 listener.expectedCode = 200; // OK
348 chan.asyncOpen(listener);
349 do_test_pending();
352 function test_proxy_wrongpw_host_returnfalse() {
353 dump("\ntest: proxy wrongpw, host return false\n");
354 var chan = makeChan();
355 chan.notificationCallbacks = new Requestor(
356 FLAG_WRONG_PASSWORD,
357 FLAG_RETURN_FALSE
359 listener.expectedCode = 401; // Host Unauthorized
360 chan.asyncOpen(listener);
361 do_test_pending();
364 var tests = [
365 test_proxy_returnfalse,
366 test_proxy_wrongpw,
367 test_all_ok,
368 test_proxy_407_cookie,
369 test_proxy_200_cookie,
370 test_host_returnfalse,
371 test_host_wrongpw,
372 test_proxy_wrongpw_host_wrongpw,
373 test_proxy_wrongpw_host_returnfalse,
376 // PATH HANDLERS
378 // Proxy
379 function proxyAuthHandler(metadata, response) {
380 try {
381 var realm = "intern";
382 // btoa("proxy:guest"), but that function is not available here
383 var expectedHeader = "Basic cHJveHk6Z3Vlc3Q=";
385 var body;
386 if (
387 metadata.hasHeader("Proxy-Authorization") &&
388 metadata.getHeader("Proxy-Authorization") == expectedHeader
390 dump("proxy password ok\n");
391 response.setHeader(
392 "Proxy-Authenticate",
393 'Basic realm="' + realm + '"',
394 false
397 hostAuthHandler(metadata, response);
398 } else {
399 dump("proxy password required\n");
400 response.setStatusLine(
401 metadata.httpVersion,
402 407,
403 "Unauthorized by HTTP proxy"
405 response.setHeader(
406 "Proxy-Authenticate",
407 'Basic realm="' + realm + '"',
408 false
410 if (metadata.hasHeader("X-Set-407-Cookie")) {
411 response.setHeader("Set-Cookie", "chewy", false);
413 body = "failed";
414 response.bodyOutputStream.write(body, body.length);
416 } catch (e) {
417 do_throw(e);
421 // Host /auth
422 function hostAuthHandler(metadata, response) {
423 try {
424 var realm = "extern";
425 // btoa("host:guest"), but that function is not available here
426 var expectedHeader = "Basic aG9zdDpndWVzdA==";
428 var body;
429 if (
430 metadata.hasHeader("Authorization") &&
431 metadata.getHeader("Authorization") == expectedHeader
433 dump("host password ok\n");
434 response.setStatusLine(
435 metadata.httpVersion,
436 200,
437 "OK, authorized for host"
439 response.setHeader(
440 "WWW-Authenticate",
441 'Basic realm="' + realm + '"',
442 false
444 body = "success";
445 } else {
446 dump("host password required\n");
447 response.setStatusLine(
448 metadata.httpVersion,
449 401,
450 "Unauthorized by HTTP server host"
452 response.setHeader(
453 "WWW-Authenticate",
454 'Basic realm="' + realm + '"',
455 false
457 body = "failed";
459 response.bodyOutputStream.write(body, body.length);
460 } catch (e) {
461 do_throw(e);