netwerk/test/unit/test_auth_proxy.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 /**
michael@0 7 * This tests the automatic login to the proxy with password,
michael@0 8 * if the password is stored and the browser is restarted.
michael@0 9 *
michael@0 10 * <copied from="test_authentication.js"/>
michael@0 11 */
michael@0 12
michael@0 13 Cu.import("resource://testing-common/httpd.js");
michael@0 14
michael@0 15 const FLAG_RETURN_FALSE = 1 << 0;
michael@0 16 const FLAG_WRONG_PASSWORD = 1 << 1;
michael@0 17 const FLAG_PREVIOUS_FAILED = 1 << 2;
michael@0 18
michael@0 19 function AuthPrompt2(proxyFlags, hostFlags) {
michael@0 20 this.proxyCred.flags = proxyFlags;
michael@0 21 this.hostCred.flags = hostFlags;
michael@0 22 }
michael@0 23 AuthPrompt2.prototype = {
michael@0 24 proxyCred : { user: "proxy", pass: "guest",
michael@0 25 realmExpected: "intern", flags : 0 },
michael@0 26 hostCred : { user: "host", pass: "guest",
michael@0 27 realmExpected: "extern", flags : 0 },
michael@0 28
michael@0 29 QueryInterface: function authprompt2_qi(iid) {
michael@0 30 if (iid.equals(Ci.nsISupports) ||
michael@0 31 iid.equals(Ci.nsIAuthPrompt2))
michael@0 32 return this;
michael@0 33 throw Cr.NS_ERROR_NO_INTERFACE;
michael@0 34 },
michael@0 35
michael@0 36 promptAuth:
michael@0 37 function ap2_promptAuth(channel, encryptionLevel, authInfo)
michael@0 38 {
michael@0 39 try {
michael@0 40
michael@0 41 // never HOST and PROXY set at the same time in prompt
michael@0 42 do_check_eq((authInfo.flags & Ci.nsIAuthInformation.AUTH_HOST) != 0,
michael@0 43 (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) == 0);
michael@0 44
michael@0 45 var isProxy = (authInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) != 0;
michael@0 46 var cred = isProxy ? this.proxyCred : this.hostCred;
michael@0 47
michael@0 48 dump("with flags: " +
michael@0 49 ((cred.flags & FLAG_WRONG_PASSWORD) !=0 ? "wrong password" : "")+" "+
michael@0 50 ((cred.flags & FLAG_PREVIOUS_FAILED) !=0 ? "previous failed" : "")+" "+
michael@0 51 ((cred.flags & FLAG_RETURN_FALSE) !=0 ? "return false" : "") + "\n");
michael@0 52
michael@0 53 // PROXY properly set by necko (checked using realm)
michael@0 54 do_check_eq(cred.realmExpected, authInfo.realm);
michael@0 55
michael@0 56 // PREVIOUS_FAILED properly set by necko
michael@0 57 do_check_eq((cred.flags & FLAG_PREVIOUS_FAILED) != 0,
michael@0 58 (authInfo.flags & Ci.nsIAuthInformation.PREVIOUS_FAILED) != 0);
michael@0 59
michael@0 60 if (cred.flags & FLAG_RETURN_FALSE)
michael@0 61 {
michael@0 62 cred.flags |= FLAG_PREVIOUS_FAILED;
michael@0 63 cred.flags &= ~FLAG_RETURN_FALSE;
michael@0 64 return false;
michael@0 65 }
michael@0 66
michael@0 67 authInfo.username = cred.user;
michael@0 68 if (cred.flags & FLAG_WRONG_PASSWORD) {
michael@0 69 authInfo.password = cred.pass + ".wrong";
michael@0 70 cred.flags |= FLAG_PREVIOUS_FAILED;
michael@0 71 // Now clear the flag to avoid an infinite loop
michael@0 72 cred.flags &= ~FLAG_WRONG_PASSWORD;
michael@0 73 } else {
michael@0 74 authInfo.password = cred.pass;
michael@0 75 cred.flags &= ~FLAG_PREVIOUS_FAILED;
michael@0 76 }
michael@0 77 return true;
michael@0 78
michael@0 79 } catch (e) { do_throw(e); }
michael@0 80 },
michael@0 81
michael@0 82 asyncPromptAuth:
michael@0 83 function ap2_async(channel, callback, context, encryptionLevel, authInfo)
michael@0 84 {
michael@0 85 try {
michael@0 86 var me = this;
michael@0 87 var allOverAndDead = false;
michael@0 88 do_execute_soon(function() {
michael@0 89 try {
michael@0 90 if (allOverAndDead)
michael@0 91 throw "already canceled";
michael@0 92 var ret = me.promptAuth(channel, encryptionLevel, authInfo);
michael@0 93 if (!ret)
michael@0 94 callback.onAuthCancelled(context, true);
michael@0 95 else
michael@0 96 callback.onAuthAvailable(context, authInfo);
michael@0 97 allOverAndDead = true;
michael@0 98 } catch (e) { do_throw(e); }
michael@0 99 });
michael@0 100 return new Cancelable(function() {
michael@0 101 if (allOverAndDead)
michael@0 102 throw "can't cancel, already ran";
michael@0 103 callback.onAuthAvailable(context, authInfo);
michael@0 104 allOverAndDead = true;
michael@0 105 });
michael@0 106 } catch (e) { do_throw(e); }
michael@0 107 }
michael@0 108 };
michael@0 109
michael@0 110 function Cancelable(onCancelFunc) {
michael@0 111 this.onCancelFunc = onCancelFunc;
michael@0 112 }
michael@0 113 Cancelable.prototype = {
michael@0 114 QueryInterface: function cancelable_qi(iid) {
michael@0 115 if (iid.equals(Ci.nsISupports) ||
michael@0 116 iid.equals(Ci.nsICancelable))
michael@0 117 return this;
michael@0 118 throw Cr.NS_ERROR_NO_INTERFACE;
michael@0 119 },
michael@0 120 cancel: function cancel() {
michael@0 121 try {
michael@0 122 this.onCancelFunc();
michael@0 123 } catch (e) { do_throw(e); }
michael@0 124 }
michael@0 125 };
michael@0 126
michael@0 127 function Requestor(proxyFlags, hostFlags) {
michael@0 128 this.proxyFlags = proxyFlags;
michael@0 129 this.hostFlags = hostFlags;
michael@0 130 }
michael@0 131 Requestor.prototype = {
michael@0 132 QueryInterface: function requestor_qi(iid) {
michael@0 133 if (iid.equals(Ci.nsISupports) ||
michael@0 134 iid.equals(Ci.nsIInterfaceRequestor))
michael@0 135 return this;
michael@0 136 throw Cr.NS_ERROR_NO_INTERFACE;
michael@0 137 },
michael@0 138
michael@0 139 getInterface: function requestor_gi(iid) {
michael@0 140 if (iid.equals(Ci.nsIAuthPrompt)) {
michael@0 141 dump("authprompt1 not implemented\n");
michael@0 142 throw Cr.NS_ERROR_NO_INTERFACE;
michael@0 143 }
michael@0 144 if (iid.equals(Ci.nsIAuthPrompt2)) {
michael@0 145 try {
michael@0 146 // Allow the prompt to store state by caching it here
michael@0 147 if (!this.prompt2)
michael@0 148 this.prompt2 = new AuthPrompt2(this.proxyFlags, this.hostFlags);
michael@0 149 return this.prompt2;
michael@0 150 } catch (e) { do_throw(e); }
michael@0 151 }
michael@0 152 throw Cr.NS_ERROR_NO_INTERFACE;
michael@0 153 },
michael@0 154
michael@0 155 prompt2: null
michael@0 156 };
michael@0 157
michael@0 158 var listener = {
michael@0 159 expectedCode: -1, // uninitialized
michael@0 160
michael@0 161 onStartRequest: function test_onStartR(request, ctx) {
michael@0 162 try {
michael@0 163 // Proxy auth cancellation return failures to avoid spoofing
michael@0 164 if (!Components.isSuccessCode(request.status) &&
michael@0 165 (this.expectedCode != 407))
michael@0 166 do_throw("Channel should have a success code!");
michael@0 167
michael@0 168 if (!(request instanceof Ci.nsIHttpChannel))
michael@0 169 do_throw("Expecting an HTTP channel");
michael@0 170
michael@0 171 do_check_eq(this.expectedCode, request.responseStatus);
michael@0 172 // If we expect 200, the request should have succeeded
michael@0 173 do_check_eq(this.expectedCode == 200, request.requestSucceeded);
michael@0 174
michael@0 175 } catch (e) {
michael@0 176 do_throw("Unexpected exception: " + e);
michael@0 177 }
michael@0 178
michael@0 179 throw Cr.NS_ERROR_ABORT;
michael@0 180 },
michael@0 181
michael@0 182 onDataAvailable: function test_ODA() {
michael@0 183 do_throw("Should not get any data!");
michael@0 184 },
michael@0 185
michael@0 186 onStopRequest: function test_onStopR(request, ctx, status) {
michael@0 187 do_check_eq(status, Cr.NS_ERROR_ABORT);
michael@0 188
michael@0 189 if (current_test < (tests.length - 1)) {
michael@0 190 // First, need to clear the auth cache
michael@0 191 Cc["@mozilla.org/network/http-auth-manager;1"]
michael@0 192 .getService(Ci.nsIHttpAuthManager)
michael@0 193 .clearAll();
michael@0 194
michael@0 195 current_test++;
michael@0 196 tests[current_test]();
michael@0 197 } else {
michael@0 198 do_test_pending();
michael@0 199 httpserv.stop(do_test_finished);
michael@0 200 }
michael@0 201
michael@0 202 do_test_finished();
michael@0 203 }
michael@0 204 };
michael@0 205
michael@0 206 function makeChan(url) {
michael@0 207 if (!url)
michael@0 208 url = "http://somesite/";
michael@0 209 var ios = Cc["@mozilla.org/network/io-service;1"]
michael@0 210 .getService(Ci.nsIIOService);
michael@0 211 var chan = ios.newChannel(url, null, null)
michael@0 212 .QueryInterface(Ci.nsIHttpChannel);
michael@0 213
michael@0 214 return chan;
michael@0 215 }
michael@0 216
michael@0 217 var current_test = 0;
michael@0 218 var httpserv = null;
michael@0 219
michael@0 220 function run_test() {
michael@0 221 httpserv = new HttpServer();
michael@0 222 httpserv.registerPathHandler("/", proxyAuthHandler);
michael@0 223 httpserv.identity.add("http", "somesite", 80);
michael@0 224 httpserv.start(-1);
michael@0 225
michael@0 226 const prefs = Cc["@mozilla.org/preferences-service;1"]
michael@0 227 .getService(Ci.nsIPrefBranch);
michael@0 228 prefs.setCharPref("network.proxy.http", "localhost");
michael@0 229 prefs.setIntPref("network.proxy.http_port", httpserv.identity.primaryPort);
michael@0 230 prefs.setCharPref("network.proxy.no_proxies_on", "");
michael@0 231 prefs.setIntPref("network.proxy.type", 1);
michael@0 232
michael@0 233 tests[current_test]();
michael@0 234 }
michael@0 235
michael@0 236 function test_proxy_returnfalse() {
michael@0 237 dump("\ntest: proxy returnfalse\n");
michael@0 238 var chan = makeChan();
michael@0 239 chan.notificationCallbacks = new Requestor(FLAG_RETURN_FALSE, 0);
michael@0 240 listener.expectedCode = 407; // Proxy Unauthorized
michael@0 241 chan.asyncOpen(listener, null);
michael@0 242
michael@0 243 do_test_pending();
michael@0 244 }
michael@0 245
michael@0 246 function test_proxy_wrongpw() {
michael@0 247 dump("\ntest: proxy wrongpw\n");
michael@0 248 var chan = makeChan();
michael@0 249 chan.notificationCallbacks = new Requestor(FLAG_WRONG_PASSWORD, 0);
michael@0 250 listener.expectedCode = 200; // Eventually OK
michael@0 251 chan.asyncOpen(listener, null);
michael@0 252 do_test_pending();
michael@0 253 }
michael@0 254
michael@0 255 function test_all_ok() {
michael@0 256 dump("\ntest: all ok\n");
michael@0 257 var chan = makeChan();
michael@0 258 chan.notificationCallbacks = new Requestor(0, 0);
michael@0 259 listener.expectedCode = 200; // OK
michael@0 260 chan.asyncOpen(listener, null);
michael@0 261 do_test_pending();
michael@0 262 }
michael@0 263
michael@0 264 function test_host_returnfalse() {
michael@0 265 dump("\ntest: host returnfalse\n");
michael@0 266 var chan = makeChan();
michael@0 267 chan.notificationCallbacks = new Requestor(0, FLAG_RETURN_FALSE);
michael@0 268 listener.expectedCode = 401; // Host Unauthorized
michael@0 269 chan.asyncOpen(listener, null);
michael@0 270
michael@0 271 do_test_pending();
michael@0 272 }
michael@0 273
michael@0 274 function test_host_wrongpw() {
michael@0 275 dump("\ntest: host wrongpw\n");
michael@0 276 var chan = makeChan();
michael@0 277 chan.notificationCallbacks = new Requestor(0, FLAG_WRONG_PASSWORD);
michael@0 278 listener.expectedCode = 200; // Eventually OK
michael@0 279 chan.asyncOpen(listener, null);
michael@0 280 do_test_pending();
michael@0 281 }
michael@0 282
michael@0 283 function test_proxy_wrongpw_host_wrongpw() {
michael@0 284 dump("\ntest: proxy wrongpw, host wrongpw\n");
michael@0 285 var chan = makeChan();
michael@0 286 chan.notificationCallbacks =
michael@0 287 new Requestor(FLAG_WRONG_PASSWORD, FLAG_WRONG_PASSWORD);
michael@0 288 listener.expectedCode = 200; // OK
michael@0 289 chan.asyncOpen(listener, null);
michael@0 290 do_test_pending();
michael@0 291 }
michael@0 292
michael@0 293 function test_proxy_wrongpw_host_returnfalse() {
michael@0 294 dump("\ntest: proxy wrongpw, host return false\n");
michael@0 295 var chan = makeChan();
michael@0 296 chan.notificationCallbacks =
michael@0 297 new Requestor(FLAG_WRONG_PASSWORD, FLAG_RETURN_FALSE);
michael@0 298 listener.expectedCode = 401; // Host Unauthorized
michael@0 299 chan.asyncOpen(listener, null);
michael@0 300 do_test_pending();
michael@0 301 }
michael@0 302
michael@0 303 var tests = [test_proxy_returnfalse, test_proxy_wrongpw, test_all_ok,
michael@0 304 test_host_returnfalse, test_host_wrongpw,
michael@0 305 test_proxy_wrongpw_host_wrongpw, test_proxy_wrongpw_host_returnfalse];
michael@0 306
michael@0 307
michael@0 308 // PATH HANDLERS
michael@0 309
michael@0 310 // Proxy
michael@0 311 function proxyAuthHandler(metadata, response) {
michael@0 312 try {
michael@0 313 var realm = "intern";
michael@0 314 // btoa("proxy:guest"), but that function is not available here
michael@0 315 var expectedHeader = "Basic cHJveHk6Z3Vlc3Q=";
michael@0 316
michael@0 317 var body;
michael@0 318 if (metadata.hasHeader("Proxy-Authorization") &&
michael@0 319 metadata.getHeader("Proxy-Authorization") == expectedHeader)
michael@0 320 {
michael@0 321 dump("proxy password ok\n");
michael@0 322 response.setHeader("Proxy-Authenticate",
michael@0 323 'Basic realm="' + realm + '"', false);
michael@0 324
michael@0 325 hostAuthHandler(metadata, response);
michael@0 326 }
michael@0 327 else
michael@0 328 {
michael@0 329 dump("proxy password required\n");
michael@0 330 response.setStatusLine(metadata.httpVersion, 407,
michael@0 331 "Unauthorized by HTTP proxy");
michael@0 332 response.setHeader("Proxy-Authenticate",
michael@0 333 'Basic realm="' + realm + '"', false);
michael@0 334 body = "failed";
michael@0 335 response.bodyOutputStream.write(body, body.length);
michael@0 336 }
michael@0 337 } catch (e) { do_throw(e); }
michael@0 338 }
michael@0 339
michael@0 340 // Host /auth
michael@0 341 function hostAuthHandler(metadata, response) {
michael@0 342 try {
michael@0 343 var realm = "extern";
michael@0 344 // btoa("host:guest"), but that function is not available here
michael@0 345 var expectedHeader = "Basic aG9zdDpndWVzdA==";
michael@0 346
michael@0 347 var body;
michael@0 348 if (metadata.hasHeader("Authorization") &&
michael@0 349 metadata.getHeader("Authorization") == expectedHeader)
michael@0 350 {
michael@0 351 dump("host password ok\n");
michael@0 352 response.setStatusLine(metadata.httpVersion, 200,
michael@0 353 "OK, authorized for host");
michael@0 354 response.setHeader("WWW-Authenticate",
michael@0 355 'Basic realm="' + realm + '"', false);
michael@0 356 body = "success";
michael@0 357 }
michael@0 358 else
michael@0 359 {
michael@0 360 dump("host password required\n");
michael@0 361 response.setStatusLine(metadata.httpVersion, 401,
michael@0 362 "Unauthorized by HTTP server host");
michael@0 363 response.setHeader("WWW-Authenticate",
michael@0 364 'Basic realm="' + realm + '"', false);
michael@0 365 body = "failed";
michael@0 366 }
michael@0 367 response.bodyOutputStream.write(body, body.length);
michael@0 368 } catch (e) { do_throw(e); }
michael@0 369 }

mercurial