netwerk/test/unit/test_auth_proxy.js

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

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

mercurial