diff options
Diffstat (limited to 'dom/webauthn/tests/test_webauthn_get_assertion.html')
-rw-r--r-- | dom/webauthn/tests/test_webauthn_get_assertion.html | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/dom/webauthn/tests/test_webauthn_get_assertion.html b/dom/webauthn/tests/test_webauthn_get_assertion.html new file mode 100644 index 0000000000..7d51ce2c4b --- /dev/null +++ b/dom/webauthn/tests/test_webauthn_get_assertion.html @@ -0,0 +1,253 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<head> + <title>Tests for GetAssertion for W3C Web Authentication</title> + <script src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="text/javascript" src="u2futil.js"></script> + <script type="text/javascript" src="pkijs/common.js"></script> + <script type="text/javascript" src="pkijs/asn1.js"></script> + <script type="text/javascript" src="pkijs/x509_schema.js"></script> + <script type="text/javascript" src="pkijs/x509_simpl.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> + + <h1>Tests for GetAssertion for W3C Web Authentication</h1> + <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1309284">Mozilla Bug 1309284</a> + + <script class="testbody" type="text/javascript"> + "use strict"; + + is(navigator.authentication, undefined, "navigator.authentication does not exist any longer"); + isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist"); + isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist"); + isnot(navigator.credentials.get, undefined, "CredentialManagement get API endpoint must exist"); + + let gAssertionChallenge = new Uint8Array(16); + window.crypto.getRandomValues(gAssertionChallenge); + + let unknownCredType = {type: "Magic", id: base64ToBytes("AAA=")}; + let unknownCred = {type: "public-key", id: base64ToBytes("AAA=")}; + let validCred = null; + + add_task(test_setup_valid_credential); + add_task(test_without_credential); + add_task(test_with_credential); + add_task(test_unexpected_option); + add_task(test_unexpected_option_with_credential); + add_task(test_unexpected_transport); + add_task(test_unknown_credential_type); + add_task(test_unknown_credential); + add_task(test_too_many_credentials); + add_task(test_unexpected_option_unknown_credential_type); + add_task(test_empty_credential_list); + add_task(() => { + // Enable USB tokens. + return SpecialPowers.pushPrefEnv({"set": [ + ["security.webauth.webauthn_enable_softtoken", false], + ["security.webauth.webauthn_enable_usbtoken", true], + ]}); + }); + add_task(test_usb_empty_credential_list); + + function requestGetAssertion(params) { + return navigator.credentials.get(params); + } + + function arrivingHereIsGood(aResult) { + ok(true, "Good result! Received a: " + aResult); + } + + function arrivingHereIsBad(aResult) { + ok(false, "Bad result! Received a: " + aResult); + } + + function expectNotAllowedError(aResult) { + ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError, got " + aResult); + } + + function expectInvalidStateError(aResult) { + ok(aResult.toString().startsWith("InvalidStateError"), "Expecting a InvalidStateError, got " + aResult); + } + + function expectTypeError(aResult) { + ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError, got " + aResult); + } + + function expectSecurityError(aResult) { + ok(aResult.toString().startsWith("SecurityError"), "Expecting a SecurityError, got " + aResult); + } + + function expectAbortError(aResult) { + is(aResult.code, DOMException.ABORT_ERR, "Expecting an AbortError"); + } + + // Set up a valid credential + async function test_setup_valid_credential() { + let publicKey = { + rp: {id: document.domain, name: "none", icon: "none"}, + user: {id: new Uint8Array(), name: "none", icon: "none", displayName: "none"}, + challenge: crypto.getRandomValues(new Uint8Array(16)), + pubKeyCredParams: [{type: "public-key", alg: cose_alg_ECDSA_w_SHA256}], + }; + + return navigator.credentials.create({publicKey}) + .then(res => validCred = {type: "public-key", id: res.rawId} ); + } + + // Test basic good call, but without giving a credential so expect failures + // this is OK by the standard, but not supported by U2F-backed authenticators + // like the soft token in use here. + async function test_without_credential() { + let publicKey = { + challenge: gAssertionChallenge + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsBad) + .catch(expectInvalidStateError); + } + + // Test with a valid credential + async function test_with_credential() { + let publicKey = { + challenge: gAssertionChallenge, + allowCredentials: [validCred] + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsGood) + .catch(arrivingHereIsBad); + } + + // Test with an unexpected option. That won't stop anything, and we'll + // fail with InvalidState just as if we had no valid credentials -- which + // we don't. + async function test_unexpected_option() { + let publicKey = { + challenge: gAssertionChallenge, + unknownValue: "hi" + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsBad) + .catch(expectInvalidStateError); + } + + // Test with an unexpected option but a valid credential + async function test_unexpected_option_with_credential() { + let publicKey = { + challenge: gAssertionChallenge, + unknownValue: "hi", + allowCredentials: [validCred] + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsGood) + .catch(arrivingHereIsBad); + } + + // Test with an unexpected transport on a valid credential + async function test_unexpected_transport() { + let cred = validCred; + cred.transports = ["unknown", "usb"]; + + let publicKey = { + challenge: gAssertionChallenge, + unknownValue: "hi", + allowCredentials: [cred] + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsGood) + .catch(arrivingHereIsBad); + } + + // Test with an unknown credential type + async function test_unknown_credential_type() { + let publicKey = { + challenge: gAssertionChallenge, + allowCredentials: [unknownCredType] + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsBad) + .catch(expectInvalidStateError); + } + + // Test with an unknown credential + async function test_unknown_credential() { + let publicKey = { + challenge: gAssertionChallenge, + allowCredentials: [unknownCred] + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsBad) + .catch(expectInvalidStateError); + } + + // Test with too many credentials + async function test_too_many_credentials() { + let tooManyCredentials = Array(21).fill(validCred); + let publicKey = { + challenge: gAssertionChallenge, + allowCredentials: tooManyCredentials, + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsBad) + .catch(expectSecurityError); + } + + // Test with an unexpected option and an unknown credential type + async function test_unexpected_option_unknown_credential_type() { + let publicKey = { + challenge: gAssertionChallenge, + unknownValue: "hi", + allowCredentials: [unknownCredType] + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsBad) + .catch(expectInvalidStateError); + } + + // Test with an empty credential list + // This will return InvalidStateError since the softotken consents, but + // there are no valid credentials. + async function test_empty_credential_list() { + let publicKey = { + challenge: gAssertionChallenge, + allowCredentials: [] + }; + + await requestGetAssertion({publicKey}) + .then(arrivingHereIsBad) + .catch(expectInvalidStateError); + } + + // Test with an empty credential list + async function test_usb_empty_credential_list() { + let publicKey = { + challenge: gAssertionChallenge, + allowCredentials: [] + }; + + let ctrl = new AbortController(); + let request = requestGetAssertion({publicKey, signal: ctrl.signal}) + .then(arrivingHereIsBad) + .catch(expectAbortError); + + // Wait a tick for the statemachine to start. + await Promise.resolve(); + + // The request should time out. We'll abort it here and will fail or + // succeed upon resolution, when the error code is checked. + ctrl.abort(); + await request; + } + </script> + +</body> +</html> |