toolkit/components/passwordmgr/test/authenticate.sjs

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/components/passwordmgr/test/authenticate.sjs	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,228 @@
     1.4 +function handleRequest(request, response)
     1.5 +{
     1.6 +  try {
     1.7 +    reallyHandleRequest(request, response);
     1.8 +  } catch (e) {
     1.9 +    response.setStatusLine("1.0", 200, "AlmostOK");
    1.10 +    response.write("Error handling request: " + e);
    1.11 +  }
    1.12 +}
    1.13 +
    1.14 +
    1.15 +function reallyHandleRequest(request, response) {
    1.16 +  var match;
    1.17 +  var requestAuth = true, requestProxyAuth = true;
    1.18 +
    1.19 +  // Allow the caller to drive how authentication is processed via the query.
    1.20 +  // Eg, http://localhost:8888/authenticate.sjs?user=foo&realm=bar
    1.21 +  // The extra ? allows the user/pass/realm checks to succeed if the name is
    1.22 +  // at the beginning of the query string.
    1.23 +  var query = "?" + request.queryString;
    1.24 +
    1.25 +  var expected_user = "", expected_pass = "", realm = "mochitest";
    1.26 +  var proxy_expected_user = "", proxy_expected_pass = "", proxy_realm = "mochi-proxy";
    1.27 +  var huge = false, plugin = false, anonymous = false, formauth = false;
    1.28 +  var authHeaderCount = 1;
    1.29 +  // user=xxx
    1.30 +  match = /[^_]user=([^&]*)/.exec(query);
    1.31 +  if (match)
    1.32 +    expected_user = match[1];
    1.33 +
    1.34 +  // pass=xxx
    1.35 +  match = /[^_]pass=([^&]*)/.exec(query);
    1.36 +  if (match)
    1.37 +    expected_pass = match[1];
    1.38 +
    1.39 +  // realm=xxx
    1.40 +  match = /[^_]realm=([^&]*)/.exec(query);
    1.41 +  if (match)
    1.42 +    realm = match[1];
    1.43 +
    1.44 +  // proxy_user=xxx
    1.45 +  match = /proxy_user=([^&]*)/.exec(query);
    1.46 +  if (match)
    1.47 +    proxy_expected_user = match[1];
    1.48 +
    1.49 +  // proxy_pass=xxx
    1.50 +  match = /proxy_pass=([^&]*)/.exec(query);
    1.51 +  if (match)
    1.52 +    proxy_expected_pass = match[1];
    1.53 +
    1.54 +  // proxy_realm=xxx
    1.55 +  match = /proxy_realm=([^&]*)/.exec(query);
    1.56 +  if (match)
    1.57 +    proxy_realm = match[1];
    1.58 +
    1.59 +  // huge=1
    1.60 +  match = /huge=1/.exec(query);
    1.61 +  if (match)
    1.62 +    huge = true;
    1.63 +
    1.64 +  // plugin=1
    1.65 +  match = /plugin=1/.exec(query);
    1.66 +  if (match)
    1.67 +    plugin = true;
    1.68 +
    1.69 +  // multiple=1
    1.70 +  match = /multiple=([^&]*)/.exec(query);
    1.71 +  if (match)
    1.72 +    authHeaderCount = match[1]+0;
    1.73 +
    1.74 +  // anonymous=1
    1.75 +  match = /anonymous=1/.exec(query);
    1.76 +  if (match)
    1.77 +    anonymous = true;
    1.78 +
    1.79 +  // formauth=1
    1.80 +  match = /formauth=1/.exec(query);
    1.81 +  if (match)
    1.82 +    formauth = true;
    1.83 +
    1.84 +  // Look for an authentication header, if any, in the request.
    1.85 +  //
    1.86 +  // EG: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
    1.87 +  // 
    1.88 +  // This test only supports Basic auth. The value sent by the client is
    1.89 +  // "username:password", obscured with base64 encoding.
    1.90 +
    1.91 +  var actual_user = "", actual_pass = "", authHeader, authPresent = false;
    1.92 +  if (request.hasHeader("Authorization")) {
    1.93 +    authPresent = true;
    1.94 +    authHeader = request.getHeader("Authorization");
    1.95 +    match = /Basic (.+)/.exec(authHeader);
    1.96 +    if (match.length != 2)
    1.97 +        throw "Couldn't parse auth header: " + authHeader;
    1.98 +
    1.99 +    var userpass = base64ToString(match[1]); // no atob() :-(
   1.100 +    match = /(.*):(.*)/.exec(userpass);
   1.101 +    if (match.length != 3)
   1.102 +        throw "Couldn't decode auth header: " + userpass;
   1.103 +    actual_user = match[1];
   1.104 +    actual_pass = match[2];
   1.105 +  } 
   1.106 +
   1.107 +  var proxy_actual_user = "", proxy_actual_pass = "";
   1.108 +  if (request.hasHeader("Proxy-Authorization")) {
   1.109 +    authHeader = request.getHeader("Proxy-Authorization");
   1.110 +    match = /Basic (.+)/.exec(authHeader);
   1.111 +    if (match.length != 2)
   1.112 +        throw "Couldn't parse auth header: " + authHeader;
   1.113 +
   1.114 +    var userpass = base64ToString(match[1]); // no atob() :-(
   1.115 +    match = /(.*):(.*)/.exec(userpass);
   1.116 +    if (match.length != 3)
   1.117 +        throw "Couldn't decode auth header: " + userpass;
   1.118 +    proxy_actual_user = match[1];
   1.119 +    proxy_actual_pass = match[2];
   1.120 +  }
   1.121 +
   1.122 +  // Don't request authentication if the credentials we got were what we
   1.123 +  // expected.
   1.124 +  if (expected_user == actual_user &&
   1.125 +    expected_pass == actual_pass) {
   1.126 +    requestAuth = false;
   1.127 +  }
   1.128 +  if (proxy_expected_user == proxy_actual_user &&
   1.129 +    proxy_expected_pass == proxy_actual_pass) {
   1.130 +    requestProxyAuth = false;
   1.131 +  }
   1.132 +
   1.133 +  if (anonymous) {
   1.134 +    if (authPresent) {
   1.135 +      response.setStatusLine("1.0", 400, "Unexpected authorization header found");
   1.136 +    } else {
   1.137 +      response.setStatusLine("1.0", 200, "Authorization header not found");
   1.138 +    }
   1.139 +  } else {
   1.140 +    if (requestProxyAuth) {
   1.141 +      response.setStatusLine("1.0", 407, "Proxy authentication required");
   1.142 +      for (i = 0; i < authHeaderCount; ++i)
   1.143 +        response.setHeader("Proxy-Authenticate", "basic realm=\"" + proxy_realm + "\"", true);
   1.144 +    } else if (requestAuth) {
   1.145 +      if (formauth && authPresent)
   1.146 +        response.setStatusLine("1.0", 403, "Form authentication required");
   1.147 +      else
   1.148 +        response.setStatusLine("1.0", 401, "Authentication required");
   1.149 +      for (i = 0; i < authHeaderCount; ++i)
   1.150 +        response.setHeader("WWW-Authenticate", "basic realm=\"" + realm + "\"", true);
   1.151 +    } else {
   1.152 +      response.setStatusLine("1.0", 200, "OK");
   1.153 +    }
   1.154 +  }
   1.155 +
   1.156 +  response.setHeader("Content-Type", "application/xhtml+xml", false);
   1.157 +  response.write("<html xmlns='http://www.w3.org/1999/xhtml'>");
   1.158 +  response.write("<p>Login: <span id='ok'>" + (requestAuth ? "FAIL" : "PASS") + "</span></p>\n");
   1.159 +  response.write("<p>Proxy: <span id='proxy'>" + (requestProxyAuth ? "FAIL" : "PASS") + "</span></p>\n");
   1.160 +  response.write("<p>Auth: <span id='auth'>" + authHeader + "</span></p>\n");
   1.161 +  response.write("<p>User: <span id='user'>" + actual_user + "</span></p>\n");
   1.162 +  response.write("<p>Pass: <span id='pass'>" + actual_pass + "</span></p>\n");
   1.163 +
   1.164 +  if (huge) {
   1.165 +    response.write("<div style='display: none'>");
   1.166 +    for (i = 0; i < 100000; i++) {
   1.167 +      response.write("123456789\n");
   1.168 +    }
   1.169 +    response.write("</div>");
   1.170 +    response.write("<span id='footnote'>This is a footnote after the huge content fill</span>");
   1.171 +  }
   1.172 +
   1.173 +  if (plugin) {
   1.174 +    response.write("<embed id='embedtest' style='width: 400px; height: 100px;' " + 
   1.175 +           "type='application/x-test'></embed>\n");
   1.176 +  }
   1.177 +
   1.178 +  response.write("</html>");
   1.179 +}
   1.180 +
   1.181 +
   1.182 +// base64 decoder
   1.183 +//
   1.184 +// Yoinked from extensions/xml-rpc/src/nsXmlRpcClient.js because btoa()
   1.185 +// doesn't seem to exist. :-(
   1.186 +/* Convert Base64 data to a string */
   1.187 +const toBinaryTable = [
   1.188 +    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
   1.189 +    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
   1.190 +    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
   1.191 +    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
   1.192 +    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
   1.193 +    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
   1.194 +    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
   1.195 +    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
   1.196 +];
   1.197 +const base64Pad = '=';
   1.198 +
   1.199 +function base64ToString(data) {
   1.200 +
   1.201 +    var result = '';
   1.202 +    var leftbits = 0; // number of bits decoded, but yet to be appended
   1.203 +    var leftdata = 0; // bits decoded, but yet to be appended
   1.204 +
   1.205 +    // Convert one by one.
   1.206 +    for (var i = 0; i < data.length; i++) {
   1.207 +        var c = toBinaryTable[data.charCodeAt(i) & 0x7f];
   1.208 +        var padding = (data[i] == base64Pad);
   1.209 +        // Skip illegal characters and whitespace
   1.210 +        if (c == -1) continue;
   1.211 +        
   1.212 +        // Collect data into leftdata, update bitcount
   1.213 +        leftdata = (leftdata << 6) | c;
   1.214 +        leftbits += 6;
   1.215 +
   1.216 +        // If we have 8 or more bits, append 8 bits to the result
   1.217 +        if (leftbits >= 8) {
   1.218 +            leftbits -= 8;
   1.219 +            // Append if not padding.
   1.220 +            if (!padding)
   1.221 +                result += String.fromCharCode((leftdata >> leftbits) & 0xff);
   1.222 +            leftdata &= (1 << leftbits) - 1;
   1.223 +        }
   1.224 +    }
   1.225 +
   1.226 +    // If there are any bits left, the base64 string was corrupted
   1.227 +    if (leftbits)
   1.228 +        throw Components.Exception('Corrupted base64 string');
   1.229 +
   1.230 +    return result;
   1.231 +}

mercurial