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/. */
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"/>
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 = {
31 realmExpected
: "intern",
34 hostCred
: { user
: "host", pass
: "guest", realmExpected
: "extern", flags
: 0 },
36 QueryInterface
: ChromeUtils
.generateQI(["nsIAuthPrompt2"]),
38 promptAuth
: function ap2_promptAuth(channel
, encryptionLevel
, authInfo
) {
40 // never HOST and PROXY set at the same time in prompt
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
;
51 ((cred
.flags
& FLAG_WRONG_PASSWORD
) != 0 ? "wrong password" : "") +
53 ((cred
.flags
& FLAG_PREVIOUS_FAILED
) != 0 ? "previous failed" : "") +
55 ((cred
.flags
& FLAG_RETURN_FALSE
) != 0 ? "return false" : "") +
59 // PROXY properly set by necko (checked using realm)
60 Assert
.equal(cred
.realmExpected
, authInfo
.realm
);
62 // PREVIOUS_FAILED properly set by necko
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
;
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
;
81 authInfo
.password
= cred
.pass
;
82 cred
.flags
&= ~FLAG_PREVIOUS_FAILED
;
90 asyncPromptAuth
: function ap2_async(
98 var allOverAndDead
= false;
99 executeSoon(function () {
101 if (allOverAndDead
) {
102 throw new Error("already canceled");
104 var ret
= me
.promptAuth(channel
, encryptionLevel
, authInfo
);
106 callback
.onAuthCancelled(context
, true);
108 callback
.onAuthAvailable(context
, authInfo
);
110 allOverAndDead
= true;
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() {
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
)) {
153 // Allow the prompt to store state by caching it here
155 this.prompt2
= new AuthPrompt2(this.proxyFlags
, this.hostFlags
);
162 throw Components
.Exception("", Cr
.NS_ERROR_NO_INTERFACE
);
169 expectedCode
: -1, // uninitialized
171 onStartRequest
: function test_onStartR(request
) {
173 // Proxy auth cancellation return failures to avoid spoofing
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
);
191 cookie
= request
.getRequestHeader("Cookie");
193 Assert
.equal(cookie
, "");
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
)
215 tests
[current_test
]();
218 httpserv
.stop(do_test_finished
);
225 function makeChan(url
) {
227 url
= "http://somesite/";
230 return NetUtil
.newChannel({
232 loadUsingSystemPrincipal
: true,
233 }).QueryInterface(Ci
.nsIHttpChannel
);
236 var current_test
= 0;
239 function run_test() {
240 httpserv
= new HttpServer();
241 httpserv
.registerPathHandler("/", proxyAuthHandler
);
242 httpserv
.identity
.add("http", "somesite", 80);
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",
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
);
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
);
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
);
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
);
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
);
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
);
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
);
340 function test_proxy_wrongpw_host_wrongpw() {
341 dump("\ntest: proxy wrongpw, host wrongpw\n");
342 var chan
= makeChan();
343 chan
.notificationCallbacks
= new Requestor(
347 listener
.expectedCode
= 200; // OK
348 chan
.asyncOpen(listener
);
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(
359 listener
.expectedCode
= 401; // Host Unauthorized
360 chan
.asyncOpen(listener
);
365 test_proxy_returnfalse
,
368 test_proxy_407_cookie
,
369 test_proxy_200_cookie
,
370 test_host_returnfalse
,
372 test_proxy_wrongpw_host_wrongpw
,
373 test_proxy_wrongpw_host_returnfalse
,
379 function proxyAuthHandler(metadata
, response
) {
381 var realm
= "intern";
382 // btoa("proxy:guest"), but that function is not available here
383 var expectedHeader
= "Basic cHJveHk6Z3Vlc3Q=";
387 metadata
.hasHeader("Proxy-Authorization") &&
388 metadata
.getHeader("Proxy-Authorization") == expectedHeader
390 dump("proxy password ok\n");
392 "Proxy-Authenticate",
393 'Basic realm="' + realm
+ '"',
397 hostAuthHandler(metadata
, response
);
399 dump("proxy password required\n");
400 response
.setStatusLine(
401 metadata
.httpVersion
,
403 "Unauthorized by HTTP proxy"
406 "Proxy-Authenticate",
407 'Basic realm="' + realm
+ '"',
410 if (metadata
.hasHeader("X-Set-407-Cookie")) {
411 response
.setHeader("Set-Cookie", "chewy", false);
414 response
.bodyOutputStream
.write(body
, body
.length
);
422 function hostAuthHandler(metadata
, response
) {
424 var realm
= "extern";
425 // btoa("host:guest"), but that function is not available here
426 var expectedHeader
= "Basic aG9zdDpndWVzdA==";
430 metadata
.hasHeader("Authorization") &&
431 metadata
.getHeader("Authorization") == expectedHeader
433 dump("host password ok\n");
434 response
.setStatusLine(
435 metadata
.httpVersion
,
437 "OK, authorized for host"
441 'Basic realm="' + realm
+ '"',
446 dump("host password required\n");
447 response
.setStatusLine(
448 metadata
.httpVersion
,
450 "Unauthorized by HTTP server host"
454 'Basic realm="' + realm
+ '"',
459 response
.bodyOutputStream
.write(body
, body
.length
);