tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_idpproxy.html (5802B)


      1 <html>
      2 <head>
      3 <meta charset="utf-8" />
      4 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
      5 <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6 </head>
      7 <body>
      8  <script class="testbody" type="application/javascript">
      9 "use strict";
     10 var { IdpSandbox } = SpecialPowers.ChromeUtils.importESModule(
     11  "resource://gre/modules/media/IdpSandbox.sys.mjs"
     12 );
     13 var dummyPayload = JSON.stringify({
     14  this: 'is',
     15  a: ['stu', 6],
     16  obj: null
     17 });
     18 
     19 function test_domain_sandbox() {
     20  var diabolical = {
     21    toString() {
     22      return 'example.com/path';
     23    }
     24  };
     25  var domains = [ 'ex/foo', 'user@ex', 'user:pass@ex', 'ex#foo', 'ex?foo',
     26                  '', 12, null, diabolical, true ];
     27  domains.forEach(function(domain) {
     28    try {
     29      var idp = new IdpSandbox(domain, undefined, window);
     30      ok(false, 'IdpSandbox allowed a bad domain: ' + domain);
     31    } catch (e) {
     32      var str = (typeof domain === 'string') ? domain : typeof domain;
     33      ok(true, 'Evil domain "' + str + '" raises exception');
     34    }
     35  });
     36 }
     37 
     38 function test_protocol_sandbox() {
     39  var protos = [ '../evil/proto', '..%2Fevil%2Fproto',
     40                 '\\evil', '%5cevil', 12, true, {} ];
     41  protos.forEach(function(proto) {
     42    try {
     43      var idp = new IdpSandbox('example.com', proto, window);
     44      ok(false, 'IdpSandbox allowed a bad protocol: ' + proto);
     45    } catch (e) {
     46      var str = (typeof proto === 'string') ? proto : typeof proto;
     47      ok(true, 'Evil protocol "' + proto + '" raises exception');
     48    }
     49  });
     50 }
     51 
     52 function idpName(hash) {
     53  return 'idp.js' + (hash ? ('#' + hash) : '');
     54 }
     55 
     56 function makeSandbox(js) {
     57  var name = js || idpName();
     58  info('Creating a sandbox for the protocol: ' + name);
     59  var sandbox = new IdpSandbox('example.com', name, window);
     60  return sandbox.start().then(idp => SpecialPowers.wrap(idp));
     61 }
     62 
     63 function test_generate_assertion() {
     64  return makeSandbox()
     65    .then(idp => idp.generateAssertion(dummyPayload,
     66                                       'https://example.net',
     67                                        {}))
     68    .then(response => {
     69      response = SpecialPowers.wrap(response);
     70      is(response.idp.domain, 'example.com', 'domain is correct');
     71      is(response.idp.protocol, 'idp.js', 'protocol is correct');
     72      ok(typeof response.assertion === 'string', 'assertion is present');
     73    });
     74 }
     75 
     76 // test that the test IdP can eat its own dogfood; which is the only way to test
     77 // validateAssertion, since that consumes the output of generateAssertion (in
     78 // theory, generateAssertion could identify a different IdP domain).
     79 
     80 function test_validate_assertion() {
     81  return makeSandbox()
     82    .then(idp => idp.generateAssertion(dummyPayload,
     83                                       'https://example.net',
     84                                       { usernameHint: 'user' }))
     85    .then(assertion => {
     86      var wrapped = SpecialPowers.wrap(assertion);
     87      return makeSandbox()
     88        .then(idp => idp.validateAssertion(wrapped.assertion,
     89                                           'https://example.net'));
     90    }).then(response => {
     91      response = SpecialPowers.wrap(response);
     92      is(response.identity, 'user@example.com');
     93      is(response.contents, dummyPayload);
     94    });
     95 }
     96 
     97 // We don't want to test the #bad or the #hang instructions,
     98 // errors of the sort those generate aren't handled by the sandbox code.
     99 function test_assertion_failure(reason) {
    100  return () => {
    101    return makeSandbox(idpName(reason))
    102      .then(idp => idp.generateAssertion('hello', 'example.net', {}))
    103      .then(r => ok(false, 'should not succeed on ' + reason),
    104            e => ok(true, 'failed correctly on ' + reason));
    105  };
    106 }
    107 
    108 function test_load_failure() {
    109  return makeSandbox('non-existent-file')
    110    .then(() => ok(false, 'Should fail to load non-existent file'),
    111          e => ok(e, 'Should fail to load non-existent file'));
    112 }
    113 
    114 function test_redirect_ok(from) {
    115  return () => {
    116    return makeSandbox(from)
    117      .then(idp => idp.generateAssertion('hello', 'example.net'))
    118      .then(r => ok(SpecialPowers.wrap(r).assertion,
    119                    'Redirect to https should be OK'));
    120  };
    121 }
    122 
    123 function test_redirect_fail(from) {
    124  return () => {
    125    return makeSandbox(from)
    126      .then(() => ok(false, 'Redirect to https should fail'),
    127            e => ok(e, 'Redirect to https should fail'));
    128  };
    129 }
    130 
    131 function test_bad_js() {
    132  return makeSandbox('idp-bad.js')
    133    .then(() => ok(false, 'Bad JS should not load'),
    134          e => ok(e, 'Bad JS should not load'));
    135 }
    136 
    137 function run_all_tests() {
    138  [
    139    test_domain_sandbox,
    140    test_protocol_sandbox,
    141    test_generate_assertion,
    142    test_validate_assertion,
    143 
    144    // fail of the IdP fails
    145    test_assertion_failure('fail'),
    146    // fail if the IdP throws
    147    test_assertion_failure('throw'),
    148    // fail if the IdP is not ready
    149    test_assertion_failure('not_ready'),
    150 
    151    test_load_failure(),
    152    // Test a redirect to an HTTPS origin, which should be OK
    153    test_redirect_ok('idp-redirect-https.js'),
    154    // Two redirects is fine too
    155    test_redirect_ok('idp-redirect-https-double.js'),
    156    // A secure redirect to a path other than /.well-known/idp-proxy/* should
    157    // also work fine.
    158    test_redirect_ok('idp-redirect-https-odd-path.js'),
    159    // A redirect to HTTP is not-cool
    160    test_redirect_fail('idp-redirect-http.js'),
    161    // Also catch tricks like https->http->https
    162    test_redirect_fail('idp-redirect-http-trick.js'),
    163 
    164    test_bad_js
    165  ].reduce((p, test) => {
    166    return p.then(test)
    167      .catch(e => ok(false, test.name + ' failed: ' +
    168                     SpecialPowers.wrap(e).message + '\n' +
    169                     SpecialPowers.wrap(e).stack));
    170  }, Promise.resolve())
    171    .then(() => SimpleTest.finish());
    172 }
    173 
    174 SimpleTest.waitForExplicitFinish();
    175 run_all_tests();
    176 </script>
    177  </body>
    178 </html>