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>