test_webauthn_crossorigin_featurepolicy.html (13285B)
1 <!DOCTYPE html> 2 <meta charset=utf-8> 3 <head> 4 <title>Tests for Publickey-Credentials-Get Feature Policy for W3C Web Authentication</title> 5 <script src="/tests/SimpleTest/SimpleTest.js"></script> 6 <script type="text/javascript" src="u2futil.js"></script> 7 <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> 8 </head> 9 <body> 10 11 <h1>Tests for Publickey-Credentials-Get Feature Policy for W3C Web Authentication</h1> 12 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1460986">Mozilla Bug 1460986</a> 13 14 <script class="testbody" type="text/javascript"> 15 "use strict"; 16 17 var gAuthenticatorId; 18 var gSameCredId; 19 var gCrossCredId; 20 21 const CROSS_DOMAIN = "example.org"; 22 23 function compare(a, b) { 24 if (a.length != b.length) return false; 25 for (let i = 0; i < a.length; i += 1) { 26 if (a[i] !== b[i]) return false; 27 } 28 return true; 29 } 30 31 function arrivingHereIsGood(aResult) { 32 ok(true, "Good result! Received a: " + aResult); 33 } 34 35 function arrivingHereIsBad(aResult) { 36 ok(false, "Bad result! Received a: " + aResult); 37 } 38 39 function expectNotAllowedError(aResult) { 40 ok(aResult == "NotAllowedError", "Expecting a NotAllowedError, got " + aResult); 41 } 42 43 function expectSameCredId(aResult) { 44 ok(compare(aResult, gSameCredId), "Expecting credential for " + document.domain); 45 } 46 47 function expectCrossCredId(aResult) { 48 ok(compare(aResult, gCrossCredId), "Expecting credential for " + CROSS_DOMAIN); 49 } 50 51 function getAssertion(id) { 52 let chall = new Uint8Array(16); 53 this.content.window.crypto.getRandomValues(chall); 54 55 let options = { 56 challenge: chall, 57 allowCredentials: [ { type: "public-key", id } ], 58 }; 59 60 return this.content.window.navigator.credentials.get({publicKey: options}) 61 .then(res => Promise.resolve(new Uint8Array(res.rawId))) 62 .catch(e => Promise.reject(e.name)); 63 } 64 65 function getAssertionAndReturnClientDataJSON(id) { 66 let chall = new Uint8Array(16); 67 this.content.window.crypto.getRandomValues(chall); 68 69 let options = { 70 challenge: chall, 71 allowCredentials: [ { type: "public-key", id } ], 72 }; 73 74 return this.content.window.navigator.credentials.get({publicKey: options}) 75 .then(res => Promise.resolve(new Uint8Array(res.response.clientDataJSON))) 76 .catch(e => Promise.reject(e.name)); 77 } 78 79 function createCredential() { 80 this.content.document.notifyUserGestureActivation(); 81 82 const cose_alg_ECDSA_w_SHA256 = -7; 83 let publicKey = { 84 rp: {id: this.content.window.document.domain, name: "none"}, 85 user: {id: new Uint8Array(), name: "none", displayName: "none"}, 86 challenge: this.content.window.crypto.getRandomValues(new Uint8Array(16)), 87 pubKeyCredParams: [{type: "public-key", alg: cose_alg_ECDSA_w_SHA256}], 88 }; 89 90 return this.content.window.navigator.credentials.create({publicKey}) 91 .then(res => Promise.resolve(new Uint8Array(res.rawId))) 92 .catch(e => Promise.reject(e.name)); 93 } 94 95 async function setup(preloadSame, preloadCross) { 96 if (!gAuthenticatorId) { 97 gAuthenticatorId = await addVirtualAuthenticator(); 98 } 99 if (gSameCredId) { 100 removeCredential(gAuthenticatorId, bytesToBase64UrlSafe(gSameCredId)); 101 gSameCredId = undefined; 102 } 103 if (gCrossCredId) { 104 removeCredential(gAuthenticatorId, bytesToBase64UrlSafe(gCrossCredId)); 105 gCrossCredId = undefined; 106 } 107 if (preloadSame) { 108 gSameCredId = await addCredential(gAuthenticatorId, document.domain).then(id => base64ToBytesUrlSafe(id)); 109 } 110 if (preloadCross) { 111 gCrossCredId = await addCredential(gAuthenticatorId, CROSS_DOMAIN).then(id => base64ToBytesUrlSafe(id)); 112 } 113 } 114 115 add_task(async function test_same_origin_iframe_allow() { 116 // Don't preload any credentials. We'll try to create one in content. 117 await setup(false, false); 118 119 let iframe = document.createElement("iframe"); 120 iframe.setAttribute("src", "https://" + document.domain + "/tests/dom/webauthn/tests/empty.html"); 121 document.body.appendChild(iframe); 122 await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true})); 123 124 ok("featurePolicy" in iframe, "we have iframe.featurePolicy"); 125 ok(iframe.featurePolicy.allowsFeature("publickey-credentials-create"), "iframe allows publickey-credentials-create"); 126 ok(iframe.featurePolicy.allowsFeature("publickey-credentials-get"), "iframe allows publickey-credentials-get"); 127 128 // We should be able to create a credential in a same-origin iframe by default. 129 is(gSameCredId, undefined); 130 gSameCredId = new Uint8Array(await SpecialPowers.spawn(iframe, [], createCredential)); 131 132 // We should be able to assert a credential in a same-origin iframe by default. 133 await SpecialPowers.spawn(iframe, [gSameCredId], getAssertion) 134 .then(expectSameCredId) 135 .catch(expectNotAllowedError); 136 137 // Assert again, but get the client data this time 138 let clientDataBuffer = await SpecialPowers.spawn(iframe, [gSameCredId], getAssertionAndReturnClientDataJSON) 139 .catch(arrivingHereIsBad); 140 141 let clientData = JSON.parse(buffer2string(clientDataBuffer)); 142 ok(!clientData.crossOrigin, "Client data shows response is same origin"); 143 is(clientData.topOrigin, undefined, "Client data does not include top origin"); 144 }); 145 146 add_task(async function test_same_origin_iframe_deny() { 147 // Preload same-origin credential to ensure we cannot assert it. 148 await setup(true, false); 149 150 let iframe = document.createElement("iframe"); 151 iframe.setAttribute("src", "https://" + document.domain + "/tests/dom/webauthn/tests/empty.html"); 152 iframe.setAttribute("allow", "publickey-credentials-create 'none'; publickey-credentials-get 'none'"); 153 document.body.appendChild(iframe); 154 await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true})); 155 156 ok("featurePolicy" in iframe, "we have iframe.featurePolicy"); 157 ok(!iframe.featurePolicy.allowsFeature("publickey-credentials-create"), "iframe does not allow publickey-credentials-create"); 158 ok(!iframe.featurePolicy.allowsFeature("publickey-credentials-get"), "iframe does not allow publickey-credentials-get"); 159 160 // We should not be able to create a credential in a same-origin iframe if 161 // the iframe does not allow publickey-credentials-create. 162 await SpecialPowers.spawn(iframe, [], createCredential) 163 .then(arrivingHereIsBad) 164 .catch(expectNotAllowedError); 165 166 // We should not be able to assert a credential in a same-origin iframe if 167 // the iframe does not allow publickey-credentials-get. 168 await SpecialPowers.spawn(iframe, [gSameCredId], getAssertion) 169 .then(arrivingHereIsBad) 170 .catch(expectNotAllowedError); 171 }); 172 173 add_task(async function test_cross_origin_iframe_allow() { 174 // Don't preload any credentials. We'll try to create one in content. 175 await setup(false, false); 176 177 let iframe = document.createElement("iframe"); 178 iframe.setAttribute("src", "https://" + CROSS_DOMAIN + "/tests/dom/webauthn/tests/empty.html"); 179 iframe.setAttribute("allow", "publickey-credentials-create https://" + CROSS_DOMAIN + "; publickey-credentials-get https://" + CROSS_DOMAIN); 180 document.body.appendChild(iframe); 181 await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true})); 182 183 ok("featurePolicy" in iframe, "we have iframe.featurePolicy"); 184 ok(iframe.featurePolicy.allowsFeature("publickey-credentials-create"), "iframe allows publickey-credentials-create"); 185 ok(iframe.featurePolicy.allowsFeature("publickey-credentials-get"), "iframe allows publickey-credentials-get"); 186 187 // We should be able to create a credential in a same-origin iframe if 188 // the iframe allows publickey-credentials-create. 189 is(gCrossCredId, undefined); 190 gCrossCredId = new Uint8Array(await SpecialPowers.spawn(iframe, [], createCredential)); 191 192 // We should be able to assert a credential in a cross-origin iframe if 193 // the iframe allows publickey-credentials-get. 194 await SpecialPowers.spawn(iframe, [gCrossCredId], getAssertion) 195 .then(expectCrossCredId) 196 .catch(arrivingHereIsBad); 197 198 // Assert again, but get the client data this time 199 let clientDataBuffer = await SpecialPowers.spawn(iframe, [gCrossCredId], getAssertionAndReturnClientDataJSON) 200 .catch(arrivingHereIsBad); 201 202 let clientData = JSON.parse(buffer2string(clientDataBuffer)); 203 ok(clientData.crossOrigin, "Client data shows response is cross origin"); 204 is(clientData.topOrigin, window.location.origin, "Top origin is correct"); 205 }); 206 207 add_task(async function test_cross_origin_iframe_deny() { 208 // Preload cross-origin credential to ensure we cannot assert it. 209 await setup(false, true); 210 211 let iframe = document.createElement("iframe"); 212 iframe.setAttribute("src", "https://" + CROSS_DOMAIN + "/tests/dom/webauthn/tests/empty.html"); 213 document.body.appendChild(iframe); 214 await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true})); 215 216 ok("featurePolicy" in iframe, "we have iframe.featurePolicy"); 217 ok(!iframe.featurePolicy.allowsFeature("publickey-credentials-create"), "iframe does not allow publickey-credentials-create"); 218 ok(!iframe.featurePolicy.allowsFeature("publickey-credentials-get"), "iframe does not allow publickey-credentials-get"); 219 220 // We should not be able to create a credential in a cross-origin iframe if 221 // the iframe does not allow publickey-credentials-create. 222 await SpecialPowers.spawn(iframe, [], createCredential) 223 .then(arrivingHereIsBad) 224 .catch(expectNotAllowedError); 225 226 // We should not be able to assert a credential in a cross-origin iframe if 227 // the iframe does not allow publickey-credentials-get. 228 await SpecialPowers.spawn(iframe, [gCrossCredId], getAssertion) 229 .then(arrivingHereIsBad) 230 .catch(expectNotAllowedError); 231 }); 232 233 add_task(async function test_cross_origin_iframe_create_but_not_get() { 234 // Don't preload any credentials. We'll try to create one in content. 235 await setup(false, false); 236 237 let iframe = document.createElement("iframe"); 238 iframe.setAttribute("src", "https://" + CROSS_DOMAIN + "/tests/dom/webauthn/tests/empty.html"); 239 iframe.setAttribute("allow", "publickey-credentials-create https://" + CROSS_DOMAIN); 240 document.body.appendChild(iframe); 241 await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true})); 242 243 ok("featurePolicy" in iframe, "we have iframe.featurePolicy"); 244 ok(iframe.featurePolicy.allowsFeature("publickey-credentials-create"), "iframe allows publickey-credentials-create"); 245 ok(!iframe.featurePolicy.allowsFeature("publickey-credentials-get"), "iframe does not allow publickey-credentials-get"); 246 247 // We should be able to create a credential in a cross-origin iframe if 248 // the iframe allows publickey-credentials-create. 249 is(gCrossCredId, undefined); 250 gCrossCredId = new Uint8Array(await SpecialPowers.spawn(iframe, [], createCredential)); 251 252 // We should not be able to assert a credential in a cross-origin iframe if 253 // the iframe does not allow publickey-credentials-get. 254 await SpecialPowers.spawn(iframe, [gCrossCredId], getAssertion) 255 .then(arrivingHereIsBad) 256 .catch(expectNotAllowedError); 257 }); 258 259 add_task(async function test_cross_origin_iframe_get_but_not_create() { 260 // Preload cross-origin credential so we can assert it. 261 await setup(false, true); 262 263 let iframe = document.createElement("iframe"); 264 iframe.setAttribute("src", "https://" + CROSS_DOMAIN + "/tests/dom/webauthn/tests/empty.html"); 265 iframe.setAttribute("allow", "publickey-credentials-get https://" + CROSS_DOMAIN); 266 document.body.appendChild(iframe); 267 await new Promise(resolve => iframe.addEventListener("load", resolve, {once: true})); 268 269 ok("featurePolicy" in iframe, "we have iframe.featurePolicy"); 270 ok(!iframe.featurePolicy.allowsFeature("publickey-credentials-create"), "iframe does not publickey-credentials-create"); 271 ok(iframe.featurePolicy.allowsFeature("publickey-credentials-get"), "iframe allows publickey-credentials-get"); 272 273 // We should not be able to create a credential in a cross-origin iframe if 274 // the iframe does not allow publickey-credentials-create. 275 await SpecialPowers.spawn(iframe, [], createCredential) 276 .then(arrivingHereIsBad) 277 .catch(expectNotAllowedError); 278 279 // We should not be able to assert a credential in a cross-origin iframe if 280 // the iframe does not allow publickey-credentials-get. 281 await SpecialPowers.spawn(iframe, [gCrossCredId], getAssertion) 282 .then(arrivingHereIsGood) 283 .catch(arrivingHereIsBad); 284 }); 285 286 </script> 287 288 </body> 289 </html>