Thu, 15 Jan 2015 15:55:04 +0100
Back out 97036ab72558 which inappropriately compared turds to third parties.
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 | } |