Bug 1436522 [wpt PR 9237] - WebAuthn WD-07 api tests, a=testonly

Automatic update from web-platform-tests
new tests based on Working Draft 7

<!-- Reviewable:start -->

<!-- Reviewable:end -->

wpt-commits: 025a5577b9a881d14783aec39d4c6963647d09a0
wpt-pr: 9237
reapplied-commits: 370e267e160568862f1fd9ec246ab5bb840f586e, fe4514c84e7ad28e46bad5da93381deb99b177f3, 7806af854343c043a2645a4034fdc7812f65daad, 9ddfd21554293dec5a4bf2e5375ae4f3c9f2ded0, 75f63c4d1ebc949647184fd60972fc7b9fd4affb, 1f3a5b496acd2288cc8cf0c32af86cb35157ea4e, 88b42bd5847abac58a62c4d6b33c1509bfce5f3d, 15c2e4c690700c6c115f8afe5e44ded10d943538, c8d461ef1437641ae7d4ea1d21e1e60cd62910b0, a6088a5f48ee299386a84d2f771902267d7355b1, 0634cd8f08ebe0905a9188fb1398c7b5f889c5dc, c8ee4a012dae506ae06bb5b2ad50942b04c1aaaa, c2c352456a4cf62dcc12f851138b04397675a445, b93a8879555d2fa7e7d4e00a275513a3a6338b35, b86e1331cb36634fd33677043b61fc0c1d8485bc, 44ddf14fd3346658c3223f13652073fafbfa48fa, a1a5840a6bb53e305ba02bcbeb215659342d0edb, 7465cb110ae5ec2e2ca73182caf5293f0efc8fd5, aad5349b3458bc3414e274b33fa86a1123901ff2, eca0907980d2769c449894a6277c60c1a306792f, 38626987c0cfd6e715cfcc6f4f1a1209191a03c5, e4a67f7ddcde6cd99348e9104bd7ed07074da44a, bb3c9990840a0fae2afc840b5952d7874785b112, 042d7adef0bdb9dc80e825c3997ace7519477c42, 99f1ea44fc7915b8b7b33bce4732fa8765fd3ac2, b81999f30c1516a70c153de51a0331d14c8faead
This commit is contained in:
Adam Powers 2018-03-06 18:31:12 +00:00 committed by James Graham
parent 8447305c9d
commit 5e8605b43d
20 changed files with 1159 additions and 107 deletions

View File

@ -359779,24 +359779,96 @@
{}
]
],
"webauthn/createcredential-badargs-attestation.https.html": [
[
"/webauthn/createcredential-badargs-attestation.https.html",
{}
]
],
"webauthn/createcredential-badargs-authnrselection.https.html": [
[
"/webauthn/createcredential-badargs-authnrselection.https.html",
{}
]
],
"webauthn/createcredential-badargs-challenge.https.html": [
[
"/webauthn/createcredential-badargs-challenge.https.html",
{}
]
],
"webauthn/createcredential-badargs-rp.https.html": [
[
"/webauthn/createcredential-badargs-rp.https.html",
{}
]
],
"webauthn/createcredential-badargs-user.https.html": [
[
"/webauthn/createcredential-badargs-user.https.html",
{}
]
],
"webauthn/createcredential-excludecredentials.https.html": [
[
"/webauthn/createcredential-excludecredentials.https.html",
{}
]
],
"webauthn/createcredential-extensions.https.html": [
[
"/webauthn/createcredential-extensions.https.html",
{}
]
],
"webauthn/createcredential-passing.https.html": [
[
"/webauthn/createcredential-passing.https.html",
{}
]
],
"webauthn/createcredential-pubkeycredparams.https.html": [
[
"/webauthn/createcredential-pubkeycredparams.https.html",
{}
]
],
"webauthn/createcredential-timeout.https.html": [
[
"/webauthn/createcredential-timeout.https.html",
{}
]
],
"webauthn/getcredential-badargs-rpid.https.html": [
[
"/webauthn/getcredential-badargs-rpid.https.html",
{}
]
],
"webauthn/getcredential-badargs-userverification.https.html": [
[
"/webauthn/getcredential-badargs-userverification.https.html",
{}
]
],
"webauthn/getcredential-extensions.https.html": [
[
"/webauthn/getcredential-extensions.https.html",
{}
]
],
"webauthn/getcredential-passing.https.html": [
[
"/webauthn/getcredential-passing.https.html",
{}
]
],
"webauthn/getcredential-timeout.https.html": [
[
"/webauthn/getcredential-timeout.https.html",
{}
]
],
"webauthn/interfaces.https.html": [
[
"/webauthn/interfaces.https.html",
@ -385855,7 +385927,7 @@
"support"
],
"./lint.whitelist": [
"2292c83ea0bd1432a7ba43e86a6b9f9fa8836e23",
"67c693358b77f86e338e779ec808d00caeb5a253",
"support"
],
"./serve.py": [
@ -593042,20 +593114,68 @@
"368ab4153a7f6843ce65ce924a3b4af92f3488ee",
"support"
],
"webauthn/createcredential-badargs-attestation.https.html": [
"397a6f0b95e75cf2b743eb208f6c79c767ec648a",
"testharness"
],
"webauthn/createcredential-badargs-authnrselection.https.html": [
"f5f5c8316551a921823bfe000031d42d91d9baa1",
"testharness"
],
"webauthn/createcredential-badargs-challenge.https.html": [
"741efba3e4c583d5983a5005803f718bdaa435b0",
"testharness"
],
"webauthn/createcredential-badargs-rp.https.html": [
"941a9bda02e22b7d54855e3a4714a49d8392fa9d",
"8ab678da79853a5c41ff142704bb4732b026e06c",
"testharness"
],
"webauthn/createcredential-badargs-user.https.html": [
"37f734eed5ecd34f6feb90bb96154e16a763140a",
"testharness"
],
"webauthn/createcredential-excludecredentials.https.html": [
"387387626892215c1552ef5e742fd32d800df4ad",
"testharness"
],
"webauthn/createcredential-extensions.https.html": [
"9642dafa7ed7ce75d5812328fcd3ac2239e33ebd",
"testharness"
],
"webauthn/createcredential-passing.https.html": [
"32a6ac38f91ec6b887e9e57519eb1603b4abcdbb",
"e89da85133f56cf0b5b78f6d6f39b43926ed9fda",
"testharness"
],
"webauthn/createcredential-pubkeycredparams.https.html": [
"009193df4404190c820618840104da8db380eaa8",
"testharness"
],
"webauthn/createcredential-timeout.https.html": [
"c0e639f8a32a1bc3553fd437a4fcf694a63960c2",
"testharness"
],
"webauthn/getcredential-badargs-rpid.https.html": [
"275511dbafc9a536f92e74ef4c0531a7d8b7a437",
"testharness"
],
"webauthn/getcredential-badargs-userverification.https.html": [
"5ac7b919d473bfc126c3e57df70c2f0defc60671",
"testharness"
],
"webauthn/getcredential-extensions.https.html": [
"ea4d0533a5939927dd9eaa5d81116dbcc2f3ccbe",
"testharness"
],
"webauthn/getcredential-passing.https.html": [
"6272128ea3af65ecb4fc40055b062a678bfbb2fd",
"1b0f77b533a4e528b3abc484ba4d74b56833131f",
"testharness"
],
"webauthn/getcredential-timeout.https.html": [
"b8c71a3fccdf39c2e35bd34a3cd42561cac5836b",
"testharness"
],
"webauthn/helpers.js": [
"e6224e8e2be8657e2e312f4197cbe0225c819cea",
"9ce729fb89ba1863fb14dfc4d567e6b544a5238d",
"support"
],
"webauthn/interfaces.https.html": [
@ -593067,11 +593187,11 @@
"support"
],
"webauthn/securecontext.http.html": [
"afc1492723d140e34027a3bdbf0d1e09843ef5d6",
"7abf48e74debed79578e39934d1b84655731a3ea",
"testharness"
],
"webauthn/securecontext.https.html": [
"7f7a7aba32b9e049c618203121fae0884936643a",
"9bdd7e09c7f468b9b0c106d4764d61e77b32131f",
"testharness"
],
"webdriver/OWNERS": [

View File

@ -226,6 +226,7 @@ SET TIMEOUT: streams/writable-streams/byte-length-queuing-strategy.js
SET TIMEOUT: user-timing/*
SET TIMEOUT: webaudio/js/lodash.js
SET TIMEOUT: webaudio/the-audio-api/the-mediaelementaudiosourcenode-interface/mediaElementAudioSourceToScriptProcessorTest.html
SET TIMEOUT: webauthn/*timeout.https.html
SET TIMEOUT: webdriver/*
SET TIMEOUT: webmessaging/*
SET TIMEOUT: websockets/*

View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.create() attestation parameter Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
// attestation bad values
new CreateCredentialsTest("options.publicKey.attestation", {}).runTest("Bad attestation parameter: attestation is empty object", new TypeError());
new CreateCredentialsTest("options.publicKey.attestation", []).runTest("Bad attestation parameter: attestation is empty array", new TypeError());
new CreateCredentialsTest("options.publicKey.attestation", null).runTest("Bad attestation parameter: attestation is null", new TypeError());
new CreateCredentialsTest("options.publicKey.attestation", "noneofyourbusiness").runTest("Bad attestation parameter: attestation is \"noneofyourbusiness\"", new TypeError());
new CreateCredentialsTest("options.publicKey.attestation", "").runTest("Bad attestation parameter: attestation is empty string", new TypeError());
});
/* JSHINT */
/* globals standardSetup, CreateCredentialsTest */
</script>

View File

@ -0,0 +1,75 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.create() authenticator selection Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
var defaultAuthnrSel = {
authenticatorAttachment: "cross-platform",
requireResidentKey: false,
userVerification: "preferred"
};
// attachment
var authnrSelAttachPlatform = cloneObject(defaultAuthnrSel);
authnrSelAttachPlatform.authenticatorAttachment = "platform";
var authnrSelBadAttachEmptyStr = cloneObject(defaultAuthnrSel);
authnrSelBadAttachEmptyStr.authenticatorAttachment = "";
var authnrSelBadAttachEmptyObj = cloneObject(defaultAuthnrSel);
authnrSelBadAttachEmptyObj.authenticatorAttachment = {};
var authnrSelBadAttachNull = cloneObject(defaultAuthnrSel);
authnrSelBadAttachNull.authenticatorAttachment = null;
// resident key
var authnrSelRkTrue = cloneObject(defaultAuthnrSel);
authnrSelRkTrue.requireResidentKey = true;
var authnrSelRkBadString = cloneObject(defaultAuthnrSel);
authnrSelRkBadString.requireResidentKey = "foo";
// user verification
var authnrSelUvRequired = cloneObject(defaultAuthnrSel);
authnrSelUvRequired.userVerification = "required";
var authnrSelBadUvEmptyStr = cloneObject(defaultAuthnrSel);
authnrSelBadUvEmptyStr.userVerification = "";
var authnrSelBadUvEmptyObj = cloneObject(defaultAuthnrSel);
authnrSelBadUvEmptyObj.userVerification = {};
var authnrSelBadUvStr = cloneObject(defaultAuthnrSel);
authnrSelBadUvStr.userVerification = "requiredshirtshoestshirt";
var authnrSelBadUvNull = cloneObject(defaultAuthnrSel);
authnrSelBadUvNull.userVerification = null;
// authenticatorSelection bad values
new CreateCredentialsTest("options.publicKey.authenticatorSelection", []).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty array", new TypeError());
new CreateCredentialsTest("options.publicKey.authenticatorSelection", null).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is null", new TypeError());
new CreateCredentialsTest("options.publicKey.authenticatorSelection", "").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is empty string", new TypeError());
new CreateCredentialsTest("options.publicKey.authenticatorSelection", "none").runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection is string", new TypeError());
// authenticatorSelection bad attachment values
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachEmptyStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is empty string", new TypeError());
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachEmptyObj).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is empty object", new TypeError());
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadAttachNull).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment is null", new TypeError());
// XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelAttachPlatform).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection attachment platform", "NotAllowedError");
// authenticatorSelection bad requireResidentKey values
// XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkTrue).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey true", "NotAllowedError");
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkBadString).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection residentKey is string", new TypeError());
// TODO: not sure if rk is "boolean" or "truthy"; add test cases if it should only accept boolean values
// authenticatorSelection bad userVerification values
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvEmptyStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification empty string", new TypeError());
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvEmptyObj).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification empty object", new TypeError());
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvStr).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification bad value", new TypeError());
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelBadUvNull).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification null", new TypeError());
// XXX: assumes this is a mock authenticator the properly reports that it is not doing userVerfication
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvRequired).runTest("Bad AuthenticatorSelectionCriteria: authenticatorSelection userVerification required", "NotAllowedError");
});
/* JSHINT */
/* globals standardSetup, CreateCredentialsTest, cloneObject */
</script>

View File

@ -0,0 +1,25 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.create() challenge Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
// bad challenge values
new CreateCredentialsTest({path: "options.publicKey.challenge", value: undefined}).runTest("Bad challenge: challenge missing", new TypeError());
new CreateCredentialsTest("options.publicKey.challenge", "hi mom").runTest("Bad challenge: challenge is string", new TypeError());
new CreateCredentialsTest("options.publicKey.challenge", null).runTest("Bad challenge: challenge is null", new TypeError());
new CreateCredentialsTest("options.publicKey.challenge", {}).runTest("Bad challenge: challenge is empty object", new TypeError());
new CreateCredentialsTest("options.publicKey.challenge", new Array()).runTest("Bad challenge: challenge is empty Array", new TypeError());
new CreateCredentialsTest("options.publicKey.challenge", new ArrayBuffer(0)).runTest("Bad challenge: challenge is empty ArrayBuffer", new TypeError());
});
/* JSHINT */
/* globals standardSetup, CreateCredentialsTest */
</script>

View File

@ -12,29 +12,29 @@ standardSetup(function() {
"use strict";
// rp bad values
new CreateCredentialsTest({path: "options.publicKey.rp", value: undefined}).testBadArgs("rp missing");
new CreateCredentialsTest("options.publicKey.rp", "hi mom").testBadArgs("rp is string");
// new CreateCredentialsTest("options.publicKey.rp", {}).testBadArgs("rp is empty object");
new CreateCredentialsTest({path: "options.publicKey.rp", value: undefined}).runTest("Bad rp: rp missing", new TypeError());
new CreateCredentialsTest("options.publicKey.rp", "hi mom").runTest("Bad rp: rp is string", new TypeError());
new CreateCredentialsTest("options.publicKey.rp", {}).runTest("Bad rp: rp is empty object", new TypeError());
// rp.id
// new CreateCredentialsTest({path: "options.publicKey.rp.id", value: undefined}).testBadArgs("rp missing id");
new CreateCredentialsTest("options.publicKey.rp.id", {}).testBadArgs("Bad rp: id is object");
new CreateCredentialsTest("options.publicKey.rp.id", null).testBadArgs("Bad rp: id is null");
new CreateCredentialsTest("options.publicKey.rp.id", "").testBadArgs("Bad rp: id is empty String");
// // rp.id
new CreateCredentialsTest("options.publicKey.rp.id", {}).runTest("Bad rp: id is object", new TypeError());
new CreateCredentialsTest("options.publicKey.rp.id", null).runTest("Bad rp: id is null", "SecurityError");
new CreateCredentialsTest("options.publicKey.rp.id", "").runTest("Bad rp: id is empty String", "SecurityError");
new CreateCredentialsTest("options.publicKey.rp.id", "invalid domain.com").runTest("Bad rp: id is invalid domain (has space)", "SecurityError");
new CreateCredentialsTest("options.publicKey.rp.id", "-invaliddomain.com").runTest("Bad rp: id is invalid domain (starts with dash)", "SecurityError");
new CreateCredentialsTest("options.publicKey.rp.id", "0invaliddomain.com").runTest("Bad rp: id is invalid domain (starts with number)", "SecurityError");
// rp.name
// new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).testBadArgs("rp missing name");
new CreateCredentialsTest("options.publicKey.rp.name", {}).testBadArgs("Bad rp: name is object");
new CreateCredentialsTest("options.publicKey.rp.name", null).testBadArgs("Bad rp: name is null");
new CreateCredentialsTest("options.publicKey.rp.name", "").testBadArgs("Bad rp: name is empty String");
// // rp.name
new CreateCredentialsTest({path: "options.publicKey.rp.name", value: undefined}).runTest("rp missing name", new TypeError());
new CreateCredentialsTest("options.publicKey.rp.name", {}).runTest("Bad rp: name is object", new TypeError());
new CreateCredentialsTest("options.publicKey.rp.name", null).runTest("Bad rp: name is null", new TypeError());
new CreateCredentialsTest("options.publicKey.rp.name", "").runTest("Bad rp: name is empty String", new TypeError());
// rp.icon
// new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).testBadArgs("rp missing icon");
new CreateCredentialsTest("options.publicKey.rp.icon", {}).testBadArgs("Bad rp: icon is object");
new CreateCredentialsTest("options.publicKey.rp.icon", null).testBadArgs("Bad rp: icon is null");
new CreateCredentialsTest("options.publicKey.rp.icon", "").testBadArgs("Bad rp: icon is empty String");
// TODO: see https://github.com/w3c/webauthn/issues/587 for the 'undefined' tests that are commented out above
// TODO: unicode tests for icon URL (see also: USVString)
// // rp.icon
new CreateCredentialsTest("options.publicKey.rp.icon", {}).runTest("Bad rp: icon is object", new TypeError());
new CreateCredentialsTest("options.publicKey.rp.icon", null).runTest("Bad rp: icon is null", new TypeError());
new CreateCredentialsTest("options.publicKey.rp.icon", "").runTest("Bad rp: icon is empty String", new TypeError());
// // TODO: unicode tests for icon URL (see also: USVString)
});
/* JSHINT */

View File

@ -0,0 +1,55 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.create() user Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
// user bad values
new CreateCredentialsTest({path: "options.publicKey.user", value: undefined}).runTest("Bad user: user missing", new TypeError());
new CreateCredentialsTest("options.publicKey.user", "hi mom").runTest("Bad user: user is string", new TypeError());
new CreateCredentialsTest("options.publicKey.user", {}).runTest("Bad user: user is empty object", new TypeError());
// // user.id
new CreateCredentialsTest({path: "options.publicKey.user.id", value: undefined}).runTest("Bad user: id is undefined", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", {}).runTest("Bad user: id is object", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", null).runTest("Bad user: id is null", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", "").runTest("Bad user: id is empty String", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", new Array()).runTest("Bad user: id is empty Array", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(0)).runTest("Bad user: id is empty ArrayBuffer", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(65)).runTest("Bad user: ArrayBuffer id is too long (65 bytes)", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", new Int16Array(33)).runTest("Bad user: Int16Array id is too long (66 bytes)", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", new Int32Array(17)).runTest("Bad user: Int32Array id is too long (68 bytes)", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", new Float32Array(17)).runTest("Bad user: Float32Array id is too long (68 bytes)", new TypeError());
new CreateCredentialsTest("options.publicKey.user.id", new Float64Array(9)).runTest("Bad user: Float64Array id is too long (72 bytes)", new TypeError());
var buf = new ArrayBuffer(65);
new CreateCredentialsTest("options.publicKey.user.id", new DataView(buf)).runTest("Bad user: id is too long (65 bytes)", new TypeError());
// // user.name
new CreateCredentialsTest({path: "options.publicKey.user.name", value: undefined}).runTest("user missing name", new TypeError());
new CreateCredentialsTest("options.publicKey.user.name", {}).runTest("Bad user: name is object", new TypeError());
new CreateCredentialsTest("options.publicKey.user.name", null).runTest("Bad user: name is null", new TypeError());
new CreateCredentialsTest("options.publicKey.user.name", "").runTest("Bad user: name is empty String", new TypeError());
// // user.icon
new CreateCredentialsTest("options.publicKey.user.icon", {}).runTest("Bad user: icon is object", new TypeError());
new CreateCredentialsTest("options.publicKey.user.icon", null).runTest("Bad user: icon is null", new TypeError());
new CreateCredentialsTest("options.publicKey.user.icon", "").runTest("Bad user: icon is empty String", new TypeError());
// // TODO: unicode tests for icon URL (see also: USVString)
// // user.displayName
new CreateCredentialsTest({path: "options.publicKey.user.displayName", value: undefined}).runTest("Bad user: displayName is undefined", new TypeError());
new CreateCredentialsTest("options.publicKey.user.displayName", {}).runTest("Bad user: displayName is object", new TypeError());
new CreateCredentialsTest("options.publicKey.user.displayName", null).runTest("Bad user: displayName is null", new TypeError());
new CreateCredentialsTest("options.publicKey.user.displayName", "").runTest("Bad user: displayName is empty String", new TypeError());
});
/* JSHINT */
/* globals standardSetup, CreateCredentialsTest */
</script>

View File

@ -0,0 +1,79 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.create() excludeCredentials Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
// bad excludeCredentials values
new CreateCredentialsTest("options.publicKey.excludeCredentials", "hi mom").runTest("Bad excludeCredentials: string", new TypeError());
new CreateCredentialsTest("options.publicKey.excludeCredentials", {}).runTest("Bad excludeCredentials: empty object", new TypeError());
// TODO: bad excludeCredentials with [{.type}] or [{.id}] or [{.transports}] wrong
// good excludeCredentials values
new CreateCredentialsTest({path: "options.publicKey.excludeCredentials", value: undefined}).runTest("excludeCredentials missing");
new CreateCredentialsTest("options.publicKey.excludeCredentials", []).runTest("excludeCredentials empty array");
// proper excludeCredentials behavior
// should error on excluding existing credential
promise_test((t) => {
var cred1;
return Promise.resolve()
.then(() => {
return createCredential();
})
.then((cred) => {
cred1 = cred;
var excludeCred = {
id: cred.rawId,
type: "public-key"
};
var args = {
options: {
publicKey: {
excludeCredentials: [excludeCred]
}
}
};
var p = createCredential(args);
return promise_rejects (t, "NotAllowedError", p, "expected to fail on excluded credenetial");
});
}, "exclude existing credential");
// should not error on excluding random credential
promise_test(() => {
return Promise.resolve()
.then(() => {
return createCredential();
})
.then(() => {
var randomCredId = new Uint8Array(162);
window.crypto.getRandomValues(randomCredId);
var excludeCred = {
id: randomCredId,
type: "public-key"
};
var args = {
options: {
publicKey: {
excludeCredentials: [excludeCred]
}
}
};
return createCredential(args);
});
}, "exclude random (non-existing) credential");
// TODO: exclude including transport type (USB, BLE, NFC)
});
/* JSHINT */
/* globals standardSetup, CreateCredentialsTest, createCredential, promise_test, promise_rejects */
</script>

View File

@ -0,0 +1,52 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.create() extensions Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
var dummyExtension = {
foo: true,
bar: "yup"
};
// bad extension values
new CreateCredentialsTest("options.publicKey.extensions", "hi mom").runTest("Bad extensions: extensions is string", new TypeError());
new CreateCredentialsTest("options.publicKey.extensions", null).runTest("Bad extensions: extensions is null", new TypeError());
new CreateCredentialsTest("options.publicKey.extensions", []).runTest("Bad extensions: extensions is empty Array", new TypeError());
new CreateCredentialsTest("options.publicKey.extensions", new ArrayBuffer(0)).runTest("Bad extensions: extensions is empty ArrayBuffer", new TypeError());
var badJson = '{"foo": true, "bar: "yup"}'; // missing quote after "bar"
new CreateCredentialsTest("options.publicKey.extensions", {foo: badJson}).runTest("Bad extensions: malformatted JSON", new TypeError());
new CreateCredentialsTest("options.publicKey.extensions", {foo: dummyExtension}).runTest("Bad extensions: JavaScript object", new TypeError());
var badExtId = {};
badExtId[createRandomString(65)] = dummyExtension;
new CreateCredentialsTest("options.publicKey.extensions", {badExtId: dummyExtension}).runTest("Bad extensions: extension ID too long", new TypeError());
// phony extensions
// TODO: not sure if this should pass or fail
// should be clarified as part of https://github.com/w3c/webauthn/pull/765
var randomExtId = {};
randomExtId[createRandomString(64)] = dummyExtension;
new CreateCredentialsTest("options.publicKey.extensions", {foo: JSON.stringify(randomExtId)}).runTest("extensions is a nonsensical JSON string");
// TODO
// defined extensions:
// * appid
// * txAuthSimple
// * txAuthGeneric
// * authnSel
// * exts
// * uvi
// * loc
// * uvm
});
/* JSHINT */
/* globals standardSetup, CreateCredentialsTest, createRandomString */
</script>

View File

@ -12,9 +12,108 @@ standardSetup(function() {
"use strict";
// CreateCredentialTest passing tests
new CreateCredentialsTest().test();
// default arguments
new CreateCredentialsTest().runTest("passing credentials.create() with default arguments");
// rp
new CreateCredentialsTest({path: "options.publicKey.rp.id", value: window.location.host}).runTest("passing credentials.create() with rpId (host and port)");
new CreateCredentialsTest({path: "options.publicKey.rp.id", value: window.location.hostname}).runTest("passing credentials.create() with rpId (hostname)");
new CreateCredentialsTest({path: "options.publicKey.rp.icon", value: undefined}).runTest("passing credentials.create() without rp.icon");
// user
new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(1)).runTest("very short user id");
new CreateCredentialsTest("options.publicKey.user.id", new ArrayBuffer(64)).runTest("max length user id");
new CreateCredentialsTest("options.publicKey.user.id", new Uint8Array(64)).runTest("Uint8Array user id");
new CreateCredentialsTest("options.publicKey.user.id", new Int8Array(64)).runTest("Int8Array user id");
new CreateCredentialsTest("options.publicKey.user.id", new Int16Array(32)).runTest("Int16Array user id");
new CreateCredentialsTest("options.publicKey.user.id", new Int32Array(16)).runTest("Int32Array user id");
new CreateCredentialsTest("options.publicKey.user.id", new Float32Array(16)).runTest("Float32Array user id");
var dvBuf1 = new ArrayBuffer(16);
new CreateCredentialsTest("options.publicKey.user.id", new DataView(dvBuf1)).runTest("DataView user id");
new CreateCredentialsTest({path: "options.publicKey.user.icon", value: undefined}).runTest("passing credentials.create() without user.icon");
// good challenge values
// all these challenges are zero-filled buffers... think anyone will complain?
new CreateCredentialsTest("options.publicKey.challenge", new Int16Array(33)).runTest("Int16Array challenge");
new CreateCredentialsTest("options.publicKey.challenge", new Int32Array(17)).runTest("Int32Array challenge");
new CreateCredentialsTest("options.publicKey.challenge", new Float32Array(17)).runTest("Float32Array challenge");
new CreateCredentialsTest("options.publicKey.challenge", new Float64Array(9)).runTest("Float64Array challenge");
var dvBuf2 = new ArrayBuffer(65);
new CreateCredentialsTest("options.publicKey.challenge", new DataView(dvBuf2)).runTest("DataView challenge");
new CreateCredentialsTest("options.publicKey.challenge", new ArrayBuffer(8192)).runTest("Absurdly large challenge");
// good pubKeyCredParams values
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", []).runTest("Bad pubKeyCredParams: pubKeyCredParams is empty Array");
const pkParamEC256 = {
type: "public-key",
alg: cose_alg_ECDSA_w_SHA256
};
const pkParamEC512 = {
type: "public-key",
alg: cose_alg_ECDSA_w_SHA512
};
// XXX: presumes all mock authenticators support EC256
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC256]).runTest("EC256 pubKeyCredParams");
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512, pkParamEC256])
.runTest("SelectEC256 pubKeyCredParams from a list");
// TODO: currently most browsers are mocking FIDO U2F, which is EC256 only
// new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512]).runTest("EC512 pubKeyCredParams");
// NOTE: excludeCredentials parameter -- see also: createcredential-excludecredentials.https.html
// timeout
new CreateCredentialsTest({path: "options.publicKey.timeout", value: undefined}).runTest("passing credentials.create() with no timeout");
// valid authenticatorSelection values
var defaultAuthnrSel = {
authenticatorAttachment: "cross-platform",
requireResidentKey: false,
userVerification: "preferred"
};
// attachment
var authnrSelAttachUndef = cloneObject(defaultAuthnrSel);
authnrSelAttachUndef.authenticatorAttachment = undefined;
// resident key
var authnrSelRkUndef = cloneObject(defaultAuthnrSel);
authnrSelRkUndef.requireResidentKey = undefined;
var authnrSelRkFalse = cloneObject(defaultAuthnrSel);
authnrSelRkFalse.requireResidentKey = false;
// user verification
var authnrSelUvUndef = cloneObject(defaultAuthnrSel);
authnrSelUvUndef.userVerification = undefined;
var authnrSelUvDiscouraged = cloneObject(defaultAuthnrSel);
authnrSelUvDiscouraged.userVerification = "discouraged";
new CreateCredentialsTest({path: "options.publicKey.authenticatorSelection", value: undefined}).runTest("authenticatorSelection is undefined");
new CreateCredentialsTest("options.publicKey.authenticatorSelection", {}).runTest("authenticatorSelection is empty object");
new CreateCredentialsTest("options.publicKey.authenticatorSelection", cloneObject(defaultAuthnrSel)).runTest("authenticatorSelection default values");
// authnr selection attachment
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelAttachUndef).runTest("authenticatorSelection attachment undefined");
// authnr selection resident key
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkUndef).runTest("authenticatorSelection residentKey undefined");
// XXX: assumes authnr is behaving like most U2F authnrs; really depends on the authnr or mock configuration
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelRkFalse).runTest("authenticatorSelection residentKey false");
// authnr selection user verification
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvUndef).runTest("authenticatorSelection userVerification undefined");
new CreateCredentialsTest("options.publicKey.authenticatorSelection", authnrSelUvDiscouraged).runTest("authenticatorSelection userVerification discouraged");
// good attestation values
new CreateCredentialsTest("options.publicKey.attestation", "none").runTest("attestation parameter: attestation is \"none\"");
new CreateCredentialsTest("options.publicKey.attestation", "indirect").runTest("attestation parameter: attestation is \"indirect\"");
new CreateCredentialsTest("options.publicKey.attestation", "direct").runTest("attestation parameter: attestation is \"direct\"");
new CreateCredentialsTest({path: "options.publicKey.attestation", value: undefined}).runTest("attestation parameter: attestation is undefined");
// TODO: test this with multiple mock authenticators to make sure that the right options are chosen when available?
// good extension values
new CreateCredentialsTest({path: "options.publicKey.extensions", value: undefined}).runTest("extensions undefined");
new CreateCredentialsTest("options.publicKey.extensions", {}).runTest("extensions are empty object");
new CreateCredentialsTest("options.publicKey.extensions", {foo: "", bar: "", bat: ""}).runTest("extensions are dict of empty strings");
});
/* JSHINT */
/* globals standardSetup, CreateCredentialsTest */
/* globals standardSetup, CreateCredentialsTest, cose_alg_ECDSA_w_SHA256, cose_alg_ECDSA_w_SHA512, cloneObject */
</script>

View File

@ -0,0 +1,66 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.create() pubKeyCredParams Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
var badType = {
type: "something-else",
alg: cose_alg_ECDSA_w_SHA512
};
var badTypeEmptyString = cloneObject(badType);
badTypeEmptyString.type = "";
var badTypeNull = cloneObject(badType);
badTypeNull.type = null;
var badTypeEmptyObj = cloneObject(badType);
badTypeEmptyObj.type = {};
var badAlg = {
type: "public-key",
alg: 42
};
var badAlgZero = cloneObject(badAlg);
badAlgZero.alg = 0;
// bad pubKeyCredParams values
new CreateCredentialsTest({path: "options.publicKey.pubKeyCredParams", value: undefined}).runTest("Bad pubKeyCredParams: pubKeyCredParams is undefined", new TypeError());
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", "hi mom").runTest("Bad pubKeyCredParams: pubKeyCredParams is string", new TypeError());
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", null).runTest("Bad pubKeyCredParams: pubKeyCredParams is null", new TypeError());
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badType]).runTest("Bad pubKeyCredParams: first param has bad type (\"something-else\")", new TypeError());
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeEmptyString]).runTest("Bad pubKeyCredParams: first param has bad type (\"\")", new TypeError());
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeNull]).runTest("Bad pubKeyCredParams: first param has bad type (null)", new TypeError());
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badTypeEmptyObj]).runTest("Bad pubKeyCredParams: first param has bad type (empty object)", new TypeError());
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlg]).runTest("Bad pubKeyCredParams: first param has bad alg (42)", "NotSupportedError");
new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [badAlgZero]).runTest("Bad pubKeyCredParams: first param has bad alg (0)", "NotSupportedError");
// TODO: come back to this when mock authenticators support multiple cryptos so that we can test the preference ranking
// function verifyEC256(res) {
// debug ("verifyEC256 got", res);
// debug ("client data JSON", ab2str(res.response.clientDataJSON));
// parseAuthenticatorData(res.response.attestationObject);
// }
// new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC256, pkParamEC512])
// .afterTest(verifyEC256)
// .runTest("EC256, EC512 pubKeyCredParams");
// function verifyEC512(res) {
// debug ("verifyEC512 got", res);
// debug ("client data JSON", ab2str(res.response.clientDataJSON));
// // parseAuthenticatorData(res.response.attestationObject);
// printHex ("clientDataJSON", res.response.clientDataJSON);
// printHex ("attestationObject", res.response.attestationObject);
// }
// new CreateCredentialsTest("options.publicKey.pubKeyCredParams", [pkParamEC512, pkParamEC256])
// .afterTest(verifyEC512)
// .runTest("EC512, EC256 pubKeyCredParams");
});
/* JSHINT */
/* globals standardSetup, CreateCredentialsTest, cose_alg_ECDSA_w_SHA512, cloneObject */
</script>

View File

@ -0,0 +1,49 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.create() timeout Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
// bad timeout values
// TODO: there is some debate as to whether MAX_UNSIGNED_LONG + 1 and / or -1 should be disallowed since they get converted to valid values internally
// new CreateCredentialsTest({path: "options.publicKey.timeout", value: -1}).runTest("Bad timeout: negative", new TypeError());
// new CreateCredentialsTest({path: "options.publicKey.timeout", value: 4294967295 + 1}).runTest("Bad timeout: too big", new TypeError());
// timeout test
// XXX: this probably always passes with most mock authenticators unless
// some setup happens right here to make sure they don't return a credential
// right away. So... uhh... I guess test this with a real authenticator if you
// want to see if it really works.
promise_test(() => {
return new Promise((resolve, reject) => {
var args = {
options: {
publicKey: {
timeout: 1
}
}
};
setTimeout(() => {
reject(new Error ("timed out"));
}, 1000);
createCredential(args).then((res) => {
resolve(res);
});
});
}, "ensure create credential times out");
// TODO: createCredential.timeout > 1s && setTimeout < 1s
// TODO: createCredential.timeout < 5s && setTimeout > 5s
});
/* JSHINT */
/* globals standardSetup, CreateCredentialsTest, createCredential, promise_test */
</script>

View File

@ -0,0 +1,35 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn credential.get() rpId Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
var credPromise = createCredential();
new GetCredentialsTest("options.publicKey.rpId", "")
.addCredential(credPromise)
.runTest("Bad rpId: empty string", "SecurityError");
new GetCredentialsTest("options.publicKey.rpId", null)
.addCredential(credPromise)
.runTest("Bad rpId: null", "SecurityError");
new GetCredentialsTest("options.publicKey.rpId", "invalid domain.com")
.addCredential(credPromise)
.runTest("Bad rpId: invalid domain (has space)", "SecurityError");
new GetCredentialsTest("options.publicKey.rpId", "-invaliddomain.com")
.addCredential(credPromise)
.runTest("Bad rpId: invalid domain (starts with dash)", "SecurityError");
new GetCredentialsTest("options.publicKey.rpId", "0invaliddomain.com")
.addCredential(credPromise)
.runTest("Bad rpId: invalid domain (starts with number)", "SecurityError");
});
/* JSHINT */
/* globals standardSetup, GetCredentialsTest, createCredential */
</script>

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.get() user verification Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
var credPromise = createCredential();
// authenticatorSelection bad userVerification values
new GetCredentialsTest("options.publicKey.userVerification", "")
.addCredential(credPromise)
.runTest("Bad userVerification: empty string", new TypeError());
new GetCredentialsTest("options.publicKey.userVerification", {})
.addCredential(credPromise)
.runTest("Bad userVerification: empty object", new TypeError());
new GetCredentialsTest("options.publicKey.userVerification", "requiredshirtshoestshirt")
.addCredential(credPromise)
.runTest("Bad userVerification: bad value", new TypeError());
new GetCredentialsTest("options.publicKey.userVerification", null)
.addCredential(credPromise)
.runTest("Bad userVerification: null", new TypeError());
// XXX: assumes this is a mock authenticator the properly reports that it is not doing userVerfication
new GetCredentialsTest("options.publicKey.userVerification", "required")
.addCredential(credPromise)
.runTest("Bad userVerification: \"required\"", "NotAllowedError");
});
/* JSHINT */
/* globals standardSetup, GetCredentialsTest, createCredential */
</script>

View File

@ -0,0 +1,69 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.get() extensions Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
var dummyExtension = {
foo: true,
bar: "yup"
};
var credPromise = createCredential();
// bad extension values
new GetCredentialsTest("options.publicKey.extensions", "hi mom")
.addCredential(credPromise)
.runTest("Bad extensions: extensions is string", new TypeError());
new GetCredentialsTest("options.publicKey.extensions", null)
.addCredential(credPromise)
.runTest("Bad extensions: extensions is null", new TypeError());
new GetCredentialsTest("options.publicKey.extensions", [])
.addCredential(credPromise)
.runTest("Bad extensions: extensions is empty Array", new TypeError());
new GetCredentialsTest("options.publicKey.extensions", new ArrayBuffer(0))
.addCredential(credPromise)
.runTest("Bad extensions: extensions is empty ArrayBuffer", new TypeError());
var badJson = '{"foo": true, "bar: "yup"}'; // missing quote after "bar"
new GetCredentialsTest("options.publicKey.extensions", {foo: badJson})
.addCredential(credPromise)
.runTest("Bad extensions: malformatted JSON", new TypeError());
new GetCredentialsTest("options.publicKey.extensions", {foo: dummyExtension})
.addCredential(credPromise)
.runTest("Bad extensions: JavaScript object", new TypeError());
var badExtId = {};
badExtId[createRandomString(65)] = dummyExtension;
new GetCredentialsTest("options.publicKey.extensions", {badExtId: dummyExtension})
.addCredential(credPromise)
.runTest("Bad extensions: extension ID too long", new TypeError());
// phony extensions
// TODO: not sure if this should pass or fail
// should be clarified as part of https://github.com/w3c/webauthn/pull/765
var randomExtId = {};
randomExtId[createRandomString(64)] = dummyExtension;
new GetCredentialsTest("options.publicKey.extensions", {foo: JSON.stringify(randomExtId)})
.addCredential(credPromise)
.runTest("extensions is a nonsensical JSON string");
// TODO
// defined extensions:
// * appid
// * txAuthSimple
// * txAuthGeneric
// * authnSel
// * exts
// * uvi
// * loc
// * uvm
});
/* JSHINT */
/* globals standardSetup, GetCredentialsTest, createRandomString, createCredential */
</script>

View File

@ -11,11 +11,56 @@
standardSetup(function() {
"use strict";
// GetCredentialsTest passing tests
// new GetCredentialsTest().addCredential();
new GetCredentialsTest().addCredential().test();
var credPromise = createCredential();
// GetCredentialsTest with default args
new GetCredentialsTest()
.addCredential(credPromise)
.runTest("passing credentials.get() with default args");
// timeout
new GetCredentialsTest({path: "options.publicKey.timeout", value: undefined})
.addCredential(credPromise)
.runTest("passing credentials.create() with no timeout");
// rpId
new GetCredentialsTest({path: "options.publicKey.rpId", value: undefined})
.addCredential(credPromise)
.runTest("rpId undefined");
new GetCredentialsTest({path: "options.publicKey.rpId", value: window.location.host})
.addCredential(credPromise)
.runTest("passing credentials.get() with rpId (host and port)");
new GetCredentialsTest({path: "options.publicKey.rpId", value: window.location.hostname})
.addCredential(credPromise)
.runTest("passing credentials.get() with rpId (hostname)");
// allowCredentials
new GetCredentialsTest({path: "options.publicKey.allowCredentials", value: undefined})
.runTest("no credential specified");
// authnr selection user verification
new GetCredentialsTest({path: "options.publicKey.userVerification", value: undefined})
.addCredential(credPromise)
.runTest("authenticatorSelection userVerification undefined");
new GetCredentialsTest("options.publicKey.userVerification", "preferred")
.addCredential(credPromise)
.runTest("authenticatorSelection userVerification preferred");
new GetCredentialsTest("options.publicKey.userVerification", "discouraged")
.addCredential(credPromise)
.runTest("authenticatorSelection userVerification discouraged");
// good extension values
new GetCredentialsTest({path: "options.publicKey.extensions", value: undefined})
.addCredential(credPromise)
.runTest("extensions undefined");
new GetCredentialsTest("options.publicKey.extensions", {})
.addCredential(credPromise)
.runTest("extensions are empty object");
new GetCredentialsTest("options.publicKey.extensions", {foo: "", bar: "", bat: ""})
.addCredential(credPromise)
.runTest("extensions are dict of empty strings");
});
/* JSHINT */
/* globals standardSetup, GetCredentialsTest */
/* globals standardSetup, GetCredentialsTest, createCredential */
</script>

View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>WebAuthn navigator.credentials.get() timeout Tests</title>
<link rel="author" title="Adam Powers" href="mailto:adam@fidoalliance.org">
<link rel="help" href="https://w3c.github.io/webauthn/#iface-credential">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src=helpers.js></script>
<body></body>
<script>
standardSetup(function() {
"use strict";
var credPromise = createCredential();
// bad timeout values
// TODO: there is some debate as to whether MAX_UNSIGNED_LONG + 1 and / or -1 should be disallowed since they get converted to valid values internally
// new GetCredentialsTest({path: "options.publicKey.timeout", value: -1})
// .addCredential(credPromise)
// .runTest("Bad timeout: negative", new TypeError());
// new GetCredentialsTest({path: "options.publicKey.timeout", value: 4294967295 + 1})
// .addCredential(credPromise)
// .runTest("Bad timeout: too big", new TypeError());
// timeout test
// XXX: this probably always passes with most mock authenticators unless
// some setup happens right here to make sure they don't return a credential
// right away. So... uhh... I guess test this with a real authenticator if you
// want to see if it really works.
var timer;
function startTimer() {
timer = setTimeout(() => {
throw new Error("Timer went off before timeout");
}, 1000);
}
function stopTimer() {
clearTimeout(timer);
}
new GetCredentialsTest({path: "options.publicKey.timeout", value: 1})
.addCredential(credPromise)
.beforeTest(startTimer)
.afterTest(stopTimer)
.runTest("ensure create credential times out");
// TODO: createCredential.timeout > 1s && setTimeout < 1s
// TODO: createCredential.timeout < 5s && setTimeout > 5s
});
/* JSHINT */
/* globals standardSetup, GetCredentialsTest, createCredential */
</script>

View File

@ -1,5 +1,4 @@
/* Useful constants for working with COSE key objects */
// Useful constants for working with COSE key objects
const cose_kty = 1;
const cose_kty_ec2 = 2;
const cose_alg = 3;
@ -10,6 +9,117 @@ const cose_crv_P256 = 1;
const cose_crv_x = -2;
const cose_crv_y = -3;
/**
* These are the default arguments that will be passed to navigator.credentials.create()
* unless modified by a specific test case
*/
var createCredentialDefaultArgs = {
options: {
publicKey: {
// Relying Party:
rp: {
name: "Acme",
icon: "https://www.w3.org/StyleSheets/TR/2016/logos/W3C"
},
// User:
user: {
id: new Uint8Array(16), // Won't survive the copy, must be rebuilt
name: "john.p.smith@example.com",
displayName: "John P. Smith",
icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
},
pubKeyCredParams: [{
type: "public-key",
alg: cose_alg_ECDSA_w_SHA256,
}],
timeout: 60000, // 1 minute
excludeCredentials: [] // No excludeList
}
}
};
/**
* These are the default arguments that will be passed to navigator.credentials.get()
* unless modified by a specific test case
*/
var getCredentialDefaultArgs = {
options: {
publicKey: {
timeout: 60000
// allowCredentials: [newCredential]
}
}
};
function createCredential(opts) {
opts = opts || {};
// set the default options
var createArgs = cloneObject(createCredentialDefaultArgs);
let challengeBytes = new Uint8Array(16);
window.crypto.getRandomValues(challengeBytes);
createArgs.options.publicKey.challenge = challengeBytes;
createArgs.options.publicKey.user.id = new Uint8Array(16);
// change the defaults with any options that were passed in
extendObject (createArgs, opts);
// create the credential, return the Promise
return navigator.credentials.create(createArgs.options);
}
function createRandomString(len) {
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for(var i = 0; i < len; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
function ab2str(buf) {
return String.fromCharCode.apply(null, new Uint8Array(buf));
}
// Useful constants for working with attestation data
const authenticator_data_user_present = 0x01;
const authenticator_data_user_verified = 0x04;
const authenticator_data_attested_cred_data = 0x40;
const authenticator_data_extension_data = 0x80;
function parseAuthenticatorData(buf) {
if (buf.byteLength < 37) {
throw new TypeError ("parseAuthenticatorData: buffer must be at least 37 bytes");
}
printHex ("authnrData", buf);
var authnrData = new DataView(buf);
var authnrDataObj = {};
authnrDataObj.length = buf.byteLength;
authnrDataObj.rpIdHash = new Uint8Array (buf.slice (0,32));
authnrDataObj.rawFlags = authnrData.getUint8(32);
authnrDataObj.counter = authnrData.getUint32(33, false);
authnrDataObj.rawCounter = [];
authnrDataObj.rawCounter[0] = authnrData.getUint8(33);
authnrDataObj.rawCounter[1] = authnrData.getUint8(34);
authnrDataObj.rawCounter[2] = authnrData.getUint8(35);
authnrDataObj.rawCounter[3] = authnrData.getUint8(36);
authnrDataObj.flags = {};
authnrDataObj.flags.userPresent = (authnrDataObj.rawFlags&authenticator_data_user_present)?true:false;
authnrDataObj.flags.userVerified = (authnrDataObj.rawFlags&authenticator_data_user_verified)?true:false;
authnrDataObj.flags.attestedCredentialData = (authnrDataObj.rawFlags&authenticator_data_attested_cred_data)?true:false;
authnrDataObj.flags.extensionData = (authnrDataObj.rawFlags&authenticator_data_extension_data)?true:false;
return authnrDataObj;
}
/**
* TestCase
*
@ -118,66 +228,127 @@ class TestCase {
/**
* run the test function with the top-level properties of the test object applied as arguments
* expects the test to pass, and then validates the results
*/
test(desc) {
promise_test(() => {
return this.doIt()
.then((ret) => {
// check the result
this.validateRet(ret);
return ret;
});
}, desc);
testPasses(desc) {
return this.doIt()
.then((ret) => {
// check the result
this.validateRet(ret);
return ret;
});
}
/**
* run the test function with the top-level properties of the test object applied as arguments
* expects the test to fail
*/
testFails(t, testDesc, expectedErr) {
return promise_rejects(t, expectedErr, this.doIt(), "Expected bad parameters to fail");
}
/**
* Runs the test that's implemented by the class by calling the doIt() function
* @param {String} desc A description of the test being run
* @param [Error|String] expectedErr A string matching an error type, such as "SecurityError" or an object with a .name value that is an error type string
*/
runTest(desc, expectedErr) {
promise_test((t) => {
return Promise.resolve().then(() => {
return this.testSetup();
}).then(() => {
if (expectedErr === undefined) {
return this.testPasses(desc);
} else {
return this.testFails(t, desc, expectedErr);
}
}).then((res) => {
return this.testTeardown(res);
})
}, desc)
}
/**
* called before runTest
* virtual method expected to be overridden by child class if needed
*/
testSetup() {
if (this.beforeTestFn) {
this.beforeTestFn.call(this);
}
return Promise.resolve();
}
/**
* Adds a callback function that gets called in the TestCase context
* and within the testing process.
*/
beforeTest(fn) {
if (typeof fn !== "function") {
throw new Error ("Tried to call non-function before test");
}
this.beforeTestFn = fn;
return this;
}
/**
* called after runTest
* virtual method expected to be overridden by child class if needed
*/
testTeardown(res) {
if (this.afterTestFn) {
this.afterTestFn.call(this, res);
}
return Promise.resolve();
}
/**
* Adds a callback function that gets called in the TestCase context
* and within the testing process. Good for validating results.
*/
afterTest(fn) {
if (typeof fn !== "function") {
throw new Error ("Tried to call non-function after test");
}
this.afterTestFn = fn;
return this;
}
/**
* validates the value returned from the test function
* virtual method expected to be overridden by child class
*/
validateRet() {
throw new Error("Not implemented");
}
/**
* calls doIt() with testObject() and expects it to fail with a TypeError()
*/
testBadArgs(testDesc) {
promise_test(function(t) {
return promise_rejects(t, new TypeError(), this.doIt(), "Expected bad parameters to fail");
}.bind(this), testDesc);
}
}
var createCredentialDefaultArgs = {
options: {
publicKey: {
// Relying Party:
rp: {
name: "Acme"
},
// User:
user: {
id: new Uint8Array(), // Won't survive the copy, must be rebuilt
name: "john.p.smith@example.com",
displayName: "John P. Smith",
icon: "https://pics.acme.com/00/p/aBjjjpqPb.png"
},
pubKeyCredParams: [{
type: "public-key",
alg: cose_alg_ECDSA_w_SHA256,
}],
timeout: 60000, // 1 minute
excludeCredentials: [] // No excludeList
}
}
};
function cloneObject(o) {
return JSON.parse(JSON.stringify(o));
}
function extendObject(dst, src) {
Object.keys(src).forEach(function(key) {
if (isSimpleObject(src[key])) {
extendObject (dst[key], src[key]);
} else {
dst[key] = src[key];
}
});
}
function isSimpleObject(o) {
return (typeof o === "object" &&
!Array.isArray(o) &&
!(o instanceof ArrayBuffer));
}
/**
* CreateCredentialTest
*
@ -198,7 +369,7 @@ class CreateCredentialsTest extends TestCase {
window.crypto.getRandomValues(challengeBytes);
this.testObject = cloneObject(createCredentialDefaultArgs);
// cloneObject can't clone the BufferSource in user.id, so let's recreate it.
this.testObject.options.publicKey.user.id = new Uint8Array();
this.testObject.options.publicKey.user.id = new Uint8Array(16);
this.testObject.options.publicKey.challenge = challengeBytes;
// how to order the properties of testObject when passing them to makeCredential
@ -235,15 +406,8 @@ class GetCredentialsTest extends TestCase {
// default arguments
let challengeBytes = new Uint8Array(16);
window.crypto.getRandomValues(challengeBytes);
this.testObject = {
options: {
publicKey: {
challenge: challengeBytes,
// timeout: 60000,
// allowCredentials: [newCredential]
}
}
};
this.testObject = cloneObject(getCredentialDefaultArgs);
this.testObject.options.publicKey.challenge = challengeBytes;
// how to order the properties of testObject when passing them to makeCredential
this.argOrder = [
@ -266,33 +430,28 @@ class GetCredentialsTest extends TestCase {
// if a Promise was passed in, add it to the list
if (arg instanceof Promise) {
this.credentialPromiseList.push(arg);
return;
return this;
}
// if a credential object was passed in, convert it to a Promise for consistency
if (typeof arg === "object") {
this.credentialPromiseList.push(Promise.resolve(arg));
return;
return this;
}
// if a credential wasn't passed in, create one
let challengeBytes = new Uint8Array(16);
window.crypto.getRandomValues(challengeBytes);
var createArgs = cloneObject(createCredentialDefaultArgs);
createArgs.options.publicKey.challenge = challengeBytes;
createArgs.options.publicKey.user.id = new Uint8Array();
var p = navigator.credentials.create(createArgs.options);
// if no credential specified then create one
var p = createCredential();
this.credentialPromiseList.push(p);
return this;
}
test() {
testSetup(desc) {
if (!this.credentialPromiseList.length) {
throw new Error("Attempting list without defining credential to test");
}
Promise.all(this.credentialPromiseList)
return Promise.all(this.credentialPromiseList)
.then((credList) => {
var idList = credList.map((cred) => {
return {
@ -302,12 +461,15 @@ class GetCredentialsTest extends TestCase {
};
});
this.testObject.options.publicKey.allowCredentials = idList;
return super.test();
// return super.test(desc);
})
.catch((err) => {
throw Error(err);
});
}
validateRet(ret) {
validatePublicKeyCredential (ret);
validatePublicKeyCredential(ret);
validateAuthenticatorAssertionResponse(ret.response);
}
}
@ -335,12 +497,16 @@ function validatePublicKeyCredential(cred) {
function validateAuthenticatorAttestationResponse(attr) {
// class
assert_class_string(attr, "AuthenticatorAttestationResponse", "Expected credentials.create() to return instance of 'AuthenticatorAttestationResponse' class");
// clientDataJSON
assert_idl_attribute(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with clientDataJSON attribute");
assert_readonly(attr, "clientDataJSON", "credentials.create() should return AuthenticatorAttestationResponse with readonly clientDataJSON attribute");
// TODO: clientDataJSON() and make sure fields are correct
// attestationObject
assert_idl_attribute(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with attestationObject attribute");
assert_readonly(attr, "attestationObject", "credentials.create() should return AuthenticatorAttestationResponse with readonly attestationObject attribute");
// TODO: parseAuthenticatorData() and make sure flags are correct
}
/**
@ -349,15 +515,20 @@ function validateAuthenticatorAttestationResponse(attr) {
function validateAuthenticatorAssertionResponse(assert) {
// class
assert_class_string(assert, "AuthenticatorAssertionResponse", "Expected credentials.create() to return instance of 'AuthenticatorAssertionResponse' class");
// clientDataJSON
assert_idl_attribute(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with clientDataJSON attribute");
assert_readonly(assert, "clientDataJSON", "credentials.get() should return AuthenticatorAssertionResponse with readonly clientDataJSON attribute");
// TODO: clientDataJSON() and make sure fields are correct
// signature
assert_idl_attribute(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with signature attribute");
assert_readonly(assert, "signature", "credentials.get() should return AuthenticatorAssertionResponse with readonly signature attribute");
// authenticatorData
assert_idl_attribute(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with authenticatorData attribute");
assert_readonly(assert, "authenticatorData", "credentials.get() should return AuthenticatorAssertionResponse with readonly authenticatorData attribute");
// TODO: parseAuthenticatorData() and make sure flags are correct
}
//************* BEGIN DELETE AFTER 1/1/2018 *************** //
@ -370,8 +541,8 @@ var debug = function() {};
// note that the polyfill only gets loaded if navigator.credentials create doesn't exist
// AND if the polyfill script is found at the right path (i.e. - the polyfill is opt-in)
function ensureInterface() {
if (typeof navigator.credentials.create !== "function") {
debug = console.log;
if (typeof navigator.credentials === "object" && typeof navigator.credentials.create !== "function") {
// debug = onsole.log;
return loadJavaScript("/webauthn/webauthn-polyfill/webauthn-polyfill.js")
.then(() => {

View File

@ -17,7 +17,7 @@ standardSetup(function() {
// Example 1
// http://example.com/ opened in a top-level browsing context is not a secure context, as it was not delivered over an authenticated and encrypted channel.
test (() => {
assert_false (typeof navigator.credentials.create === "function");
assert_false (typeof navigator.credentials === "object" && typeof navigator.credentials.create === "function");
}, "no navigator.credentials.create in non-secure context");
// Example 4: TODO

View File

@ -17,7 +17,7 @@ standardSetup(function() {
// Example 2
// https://example.com/ opened in a top-level browsing context is a secure context, as it was delivered over an authenticated and encrypted channel.
test (() => {
assert_true (typeof navigator.credentials.create === "function");
assert_true (typeof navigator.credentials === "object" && typeof navigator.credentials.create === "function");
}, "navigator.credentials.create exists in secure context");
// Example 3: TODO