bug 1332681 - part 3/4 - convert authentication.makeCredential to credentials.create r=jcj,qdot

MozReview-Commit-ID: 1xfsQqGCEcl

--HG--
rename : dom/webauthn/WebAuthentication.cpp => dom/credentialmanagement/CredentialsContainer.cpp
rename : dom/webauthn/WebAuthentication.h => dom/credentialmanagement/CredentialsContainer.h
extra : rebase_source : d92546a7f6a3780c6ec8790dfabb23a9ea29efbe
This commit is contained in:
David Keeler 2017-05-22 17:09:49 -07:00
Родитель 0ecb59e4a9
Коммит abac00aea3
21 изменённых файлов: 630 добавлений и 560 удалений

Просмотреть файл

@ -33,6 +33,7 @@
#include "mozilla/Preferences.h"
#include "mozilla/Telemetry.h"
#include "BatteryManager.h"
#include "mozilla/dom/CredentialsContainer.h"
#include "mozilla/dom/GamepadServiceTest.h"
#include "mozilla/dom/PowerManager.h"
#include "mozilla/dom/WakeLock.h"
@ -206,6 +207,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Navigator)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConnection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStorageManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAuthentication)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCredentials)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMediaDevices)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTimeManager)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mServiceWorkerContainer)
@ -2010,5 +2012,14 @@ Navigator::Authentication()
return mAuthentication;
}
CredentialsContainer*
Navigator::Credentials()
{
if (!mCredentials) {
mCredentials = new CredentialsContainer(GetWindow());
}
return mCredentials;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -43,6 +43,7 @@ class DOMRequest;
struct FlyWebPublishOptions;
struct FlyWebFilter;
class WebAuthentication;
class CredentialsContainer;
} // namespace dom
} // namespace mozilla
@ -226,6 +227,7 @@ public:
already_AddRefed<ServiceWorkerContainer> ServiceWorker();
mozilla::dom::WebAuthentication* Authentication();
mozilla::dom::CredentialsContainer* Credentials();
void GetLanguages(nsTArray<nsString>& aLanguages);
@ -295,6 +297,7 @@ private:
RefPtr<PowerManager> mPowerManager;
RefPtr<network::Connection> mConnection;
RefPtr<WebAuthentication> mAuthentication;
RefPtr<CredentialsContainer> mCredentials;
RefPtr<MediaDevices> mMediaDevices;
RefPtr<time::TimeManager> mTimeManager;
RefPtr<ServiceWorkerContainer> mServiceWorkerContainer;

Просмотреть файл

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/CredentialsContainer.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/WebAuthnManager.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(CredentialsContainer, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(CredentialsContainer)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CredentialsContainer)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CredentialsContainer)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
CredentialsContainer::CredentialsContainer(nsPIDOMWindowInner* aParent) :
mParent(aParent)
{
MOZ_ASSERT(aParent);
}
CredentialsContainer::~CredentialsContainer()
{}
JSObject*
CredentialsContainer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return CredentialsContainerBinding::Wrap(aCx, this, aGivenProto);
}
already_AddRefed<Promise>
CredentialsContainer::Create(const CredentialCreationOptions& aOptions)
{
RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
MOZ_ASSERT(mgr);
return mgr->MakeCredential(mParent, aOptions.mPublicKey);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_CredentialsContainer_h
#define mozilla_dom_CredentialsContainer_h
#include "mozilla/dom/CredentialManagementBinding.h"
namespace mozilla {
namespace dom {
class CredentialsContainer final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CredentialsContainer)
explicit CredentialsContainer(nsPIDOMWindowInner* aParent);
nsPIDOMWindowInner*
GetParentObject() const
{
return mParent;
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
already_AddRefed<Promise>
Create(const CredentialCreationOptions& aOptions);
private:
~CredentialsContainer();
nsCOMPtr<nsPIDOMWindowInner> mParent;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_CredentialsContainer_h

Просмотреть файл

@ -9,10 +9,14 @@ with Files("**"):
EXPORTS.mozilla.dom += [
'Credential.h',
'CredentialsContainer.h',
]
UNIFIED_SOURCES += [
'Credential.cpp',
'CredentialsContainer.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

Просмотреть файл

@ -20,11 +20,7 @@ namespace mozilla {
namespace dom {
struct WebAuthnScopedCredentialDescriptor {
// Converted from mozilla::dom::ScopedCredentialType enum
uint32_t type;
uint8_t[] id;
// Converted from mozilla::dom::WebAuthnTransport enum
uint32_t[] transports;
};
struct WebAuthnExtension {

Просмотреть файл

@ -1,66 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/ScopedCredential.h"
#include "mozilla/dom/WebAuthenticationBinding.h"
namespace mozilla {
namespace dom {
// Only needed for refcounted objects.
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(ScopedCredential, mParent)
NS_IMPL_CYCLE_COLLECTING_ADDREF(ScopedCredential)
NS_IMPL_CYCLE_COLLECTING_RELEASE(ScopedCredential)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScopedCredential)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
ScopedCredential::ScopedCredential(nsPIDOMWindowInner* aParent)
: mParent(aParent)
, mType(ScopedCredentialType::ScopedCred)
{}
ScopedCredential::~ScopedCredential()
{}
JSObject*
ScopedCredential::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return ScopedCredentialBinding::Wrap(aCx, this, aGivenProto);
}
ScopedCredentialType
ScopedCredential::Type() const
{
return mType;
}
void
ScopedCredential::GetId(JSContext* aCx,
JS::MutableHandle<JSObject*> aRetVal) const
{
aRetVal.set(mIdBuffer.ToUint8Array(aCx));
}
nsresult
ScopedCredential::SetType(ScopedCredentialType aType)
{
mType = aType;
return NS_OK;
}
nsresult
ScopedCredential::SetId(CryptoBuffer& aBuffer)
{
if (!mIdBuffer.Assign(aBuffer)) {
return NS_ERROR_OUT_OF_MEMORY;
}
return NS_OK;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -1,66 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_ScopedCredential_h
#define mozilla_dom_ScopedCredential_h
#include "js/TypeDecls.h"
#include "mozilla/Attributes.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/CryptoBuffer.h"
#include "mozilla/dom/WebAuthenticationBinding.h"
#include "nsCycleCollectionParticipant.h"
#include "nsWrapperCache.h"
namespace mozilla {
namespace dom {
class ScopedCredential final : public nsISupports
, public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScopedCredential)
public:
explicit ScopedCredential(nsPIDOMWindowInner* aParent);
protected:
~ScopedCredential();
public:
nsISupports*
GetParentObject() const
{
return mParent;
}
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
ScopedCredentialType
Type() const;
void
GetId(JSContext* aCx, JS::MutableHandle<JSObject*> aRetVal) const;
nsresult
SetType(ScopedCredentialType aType);
nsresult
SetId(CryptoBuffer& aBuffer);
private:
nsCOMPtr<nsPIDOMWindowInner> mParent;
CryptoBuffer mIdBuffer;
ScopedCredentialType mType;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_ScopedCredential_h

Просмотреть файл

@ -34,17 +34,6 @@ WebAuthentication::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
return WebAuthenticationBinding::Wrap(aCx, this, aGivenProto);
}
already_AddRefed<Promise>
WebAuthentication::MakeCredential(JSContext* aCx, const Account& aAccount,
const Sequence<ScopedCredentialParameters>& aCryptoParameters,
const ArrayBufferViewOrArrayBuffer& aChallenge,
const ScopedCredentialOptions& aOptions)
{
RefPtr<WebAuthnManager> mgr = WebAuthnManager::GetOrCreate();
MOZ_ASSERT(mgr);
return mgr->MakeCredential(mParent, aCx, aAccount, aCryptoParameters, aChallenge, aOptions);
}
already_AddRefed<Promise>
WebAuthentication::GetAssertion(const ArrayBufferViewOrArrayBuffer& aChallenge,
const AssertionOptions& aOptions)

Просмотреть файл

@ -42,12 +42,6 @@ public:
virtual JSObject*
WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
already_AddRefed<Promise>
MakeCredential(JSContext* aCx, const Account& accountInformation,
const Sequence<ScopedCredentialParameters>& cryptoParameters,
const ArrayBufferViewOrArrayBuffer& attestationChallenge,
const ScopedCredentialOptions& options);
already_AddRefed<Promise>
GetAssertion(const ArrayBufferViewOrArrayBuffer& assertionChallenge,
const AssertionOptions& options);

Просмотреть файл

@ -40,7 +40,7 @@ NS_IMPL_ISUPPORTS(WebAuthnManager, nsIIPCBackgroundChildCreateCallback);
template<class OOS>
static nsresult
GetAlgorithmName(JSContext* aCx, const OOS& aAlgorithm,
GetAlgorithmName(const OOS& aAlgorithm,
/* out */ nsString& aName)
{
MOZ_ASSERT(aAlgorithm.IsString()); // TODO: remove assertion when we coerce.
@ -100,10 +100,10 @@ AssembleClientData(const nsAString& aOrigin, const CryptoBuffer& aChallenge,
return NS_ERROR_FAILURE;
}
WebAuthnClientData clientDataObject;
clientDataObject.mOrigin.Assign(aOrigin);
clientDataObject.mHashAlg.SetAsString().Assign(NS_LITERAL_STRING("S256"));
CollectedClientData clientDataObject;
clientDataObject.mChallenge.Assign(challengeBase64);
clientDataObject.mOrigin.Assign(aOrigin);
clientDataObject.mHashAlg.Assign(NS_LITERAL_STRING("S256"));
nsAutoString temp;
if (NS_WARN_IF(!clientDataObject.ToJSON(temp))) {
@ -215,11 +215,8 @@ WebAuthnManager::Get()
}
already_AddRefed<Promise>
WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
const Account& aAccountInformation,
const Sequence<ScopedCredentialParameters>& aCryptoParameters,
const ArrayBufferViewOrArrayBuffer& aChallenge,
const ScopedCredentialOptions& aOptions)
WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent,
const MakeCredentialOptions& aOptions)
{
MOZ_ASSERT(aParent);
@ -245,15 +242,15 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
// closest value lying within that range.
double adjustedTimeout = 30.0;
if (aOptions.mTimeoutSeconds.WasPassed()) {
adjustedTimeout = aOptions.mTimeoutSeconds.Value();
if (aOptions.mTimeout.WasPassed()) {
adjustedTimeout = aOptions.mTimeout.Value();
adjustedTimeout = std::max(15.0, adjustedTimeout);
adjustedTimeout = std::min(120.0, adjustedTimeout);
}
nsCString rpId;
if (!aOptions.mRpId.WasPassed()) {
// If rpId is not specified, then set rpId to callerOrigin, and rpIdHash to
if (!aOptions.mRp.mId.WasPassed()) {
// If rp.id is not specified, then set rpId to callerOrigin, and rpIdHash to
// the SHA-256 hash of rpId.
rpId.Assign(NS_ConvertUTF16toUTF8(origin));
} else {
@ -265,7 +262,7 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
// Otherwise, reject promise with a DOMException whose name is
// "SecurityError", and terminate this algorithm.
if (NS_FAILED(RelaxSameOrigin(aParent, aOptions.mRpId.Value(), rpId))) {
if (NS_FAILED(RelaxSameOrigin(aParent, aOptions.mRp.mId.Value(), rpId))) {
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
return promise.forget();
}
@ -293,15 +290,15 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
// Process each element of cryptoParameters using the following steps, to
// produce a new sequence normalizedParameters.
nsTArray<ScopedCredentialParameters> normalizedParams;
for (size_t a = 0; a < aCryptoParameters.Length(); ++a) {
nsTArray<PublicKeyCredentialParameters> normalizedParams;
for (size_t a = 0; a < aOptions.mParameters.Length(); ++a) {
// Let current be the currently selected element of
// cryptoParameters.
// If current.type does not contain a ScopedCredentialType
// If current.type does not contain a PublicKeyCredentialType
// supported by this implementation, then stop processing current and move
// on to the next element in cryptoParameters.
if (aCryptoParameters[a].mType != ScopedCredentialType::ScopedCred) {
if (aOptions.mParameters[a].mType != PublicKeyCredentialType::Public_key) {
continue;
}
@ -312,16 +309,16 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
// element in cryptoParameters.
nsString algName;
if (NS_FAILED(GetAlgorithmName(aCx, aCryptoParameters[a].mAlgorithm,
if (NS_FAILED(GetAlgorithmName(aOptions.mParameters[a].mAlgorithm,
algName))) {
continue;
}
// Add a new object of type ScopedCredentialParameters to
// Add a new object of type PublicKeyCredentialParameters to
// normalizedParameters, with type set to current.type and algorithm set to
// normalizedAlgorithm.
ScopedCredentialParameters normalizedObj;
normalizedObj.mType = aCryptoParameters[a].mType;
PublicKeyCredentialParameters normalizedObj;
normalizedObj.mType = aOptions.mParameters[a].mType;
normalizedObj.mAlgorithm.SetAsString().Assign(algName);
if (!normalizedParams.AppendElement(normalizedObj, mozilla::fallible)){
@ -333,7 +330,7 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
// If normalizedAlgorithm is empty and cryptoParameters was not empty, cancel
// the timer started in step 2, reject promise with a DOMException whose name
// is "NotSupportedError", and terminate this algorithm.
if (normalizedParams.IsEmpty() && !aCryptoParameters.IsEmpty()) {
if (normalizedParams.IsEmpty() && !aOptions.mParameters.IsEmpty()) {
promise->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
return promise.forget();
}
@ -341,16 +338,17 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
// TODO: The following check should not be here. This is checking for
// parameters specific to the soft key, and should be put in the soft key
// manager in the parent process. Still need to serialize
// ScopedCredentialParameters first.
// PublicKeyCredentialParameters first.
// Check if at least one of the specified combinations of ScopedCredentialType
// and cryptographic parameters is supported. If not, return an error code
// equivalent to NotSupportedError and terminate the operation.
// Check if at least one of the specified combinations of
// PublicKeyCredentialParameters and cryptographic parameters is supported. If
// not, return an error code equivalent to NotSupportedError and terminate the
// operation.
bool isValidCombination = false;
for (size_t a = 0; a < normalizedParams.Length(); ++a) {
if (normalizedParams[a].mType == ScopedCredentialType::ScopedCred &&
if (normalizedParams[a].mType == PublicKeyCredentialType::Public_key &&
normalizedParams[a].mAlgorithm.IsString() &&
normalizedParams[a].mAlgorithm.GetAsString().EqualsLiteral(
WEBCRYPTO_NAMED_CURVE_P256)) {
@ -379,7 +377,7 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
// and compute the clientDataJSON and clientDataHash.
CryptoBuffer challenge;
if (!challenge.Assign(aChallenge)) {
if (!challenge.Assign(aOptions.mChallenge)) {
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
return promise.forget();
}
@ -407,15 +405,9 @@ WebAuthnManager::MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
if (aOptions.mExcludeList.WasPassed()) {
for (const auto& s: aOptions.mExcludeList.Value()) {
WebAuthnScopedCredentialDescriptor c;
c.type() = static_cast<uint32_t>(s.mType);
CryptoBuffer cb;
cb.Assign(s.mId);
c.id() = cb;
if (s.mTransports.WasPassed()) {
for (const auto& t: s.mTransports.Value()) {
c.transports().AppendElement(static_cast<uint32_t>(t));
}
}
excludeList.AppendElement(c);
}
}
@ -576,15 +568,9 @@ WebAuthnManager::GetAssertion(nsPIDOMWindowInner* aParent,
nsTArray<WebAuthnScopedCredentialDescriptor> allowList;
for (const auto& s: aOptions.mAllowList.Value()) {
WebAuthnScopedCredentialDescriptor c;
c.type() = static_cast<uint32_t>(s.mType);
CryptoBuffer cb;
cb.Assign(s.mId);
c.id() = cb;
if (s.mTransports.WasPassed()) {
for (const auto& t: s.mTransports.Value()) {
c.transports().AppendElement(static_cast<uint32_t>(t));
}
}
allowList.AppendElement(c);
}

Просмотреть файл

@ -7,9 +7,9 @@
#ifndef mozilla_dom_WebAuthnManager_h
#define mozilla_dom_WebAuthnManager_h
#include "nsIIPCBackgroundChildCreateCallback.h"
#include "mozilla/MozPromise.h"
#include "mozilla/dom/PWebAuthnTransaction.h"
#include "nsIIPCBackgroundChildCreateCallback.h"
/*
* Content process manager for the WebAuthn protocol. Created on calls to the
@ -73,11 +73,8 @@ public:
Cancel(const nsresult& aError);
already_AddRefed<Promise>
MakeCredential(nsPIDOMWindowInner* aParent, JSContext* aCx,
const Account& aAccountInformation,
const Sequence<ScopedCredentialParameters>& aCryptoParameters,
const ArrayBufferViewOrArrayBuffer& aAttestationChallenge,
const ScopedCredentialOptions& aOptions);
MakeCredential(nsPIDOMWindowInner* aParent,
const MakeCredentialOptions& aOptions);
already_AddRefed<Promise>
GetAssertion(nsPIDOMWindowInner* aParent,

Просмотреть файл

@ -17,7 +17,6 @@ EXPORTS.mozilla.dom += [
'AuthenticatorResponse.h',
'NSSU2FTokenRemote.h',
'PublicKeyCredential.h',
'ScopedCredential.h',
'U2FSoftTokenManager.h',
'U2FTokenManager.h',
'U2FTokenTransport.h',
@ -35,7 +34,6 @@ UNIFIED_SOURCES += [
'AuthenticatorResponse.cpp',
'NSSU2FTokenRemote.cpp',
'PublicKeyCredential.cpp',
'ScopedCredential.cpp',
'U2FSoftTokenManager.cpp',
'U2FTokenManager.cpp',
'WebAuthentication.cpp',

Просмотреть файл

@ -43,8 +43,10 @@
function runTests() {
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
let authn = navigator.authentication;

Просмотреть файл

@ -26,10 +26,13 @@ SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
["security.webauth.webauthn_enable_usbtoken", false]]},
function() {
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
let authn = navigator.authentication;
let credm = navigator.credentials;
let gCredentialChallenge = new Uint8Array(16);
window.crypto.getRandomValues(gCredentialChallenge);
@ -103,10 +106,16 @@ function() {
}
function testMakeCredential() {
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
let param = {type: "ScopedCred", algorithm: "p-256"};
authn.makeCredential(acct, [param], gCredentialChallenge)
let rp = {id: document.origin, name: "none", icon: "none"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "P-256"};
let makeCredentialOptions = {
rp: rp,
user: user,
challenge: gCredentialChallenge,
parameters: [param]
};
credm.create({publicKey: makeCredentialOptions})
.then(checkCredentialValid)
.then(testMakeDuplicate)
.catch(function(aReason) {
@ -116,14 +125,18 @@ function() {
}
function testMakeDuplicate(aCredInfo) {
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
let param = {type: "ScopedCred", algorithm: "p-256"};
let options = {rpId: document.origin,
excludeList: [{type: "ScopedCred",
id: Uint8Array.from(aCredInfo.rawId),
transports: ["usb"]}]};
authn.makeCredential(acct, [param], gCredentialChallenge, options)
let rp = {id: document.origin, name: "none", icon: "none"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "P-256"};
let makeCredentialOptions = {
rp: rp,
user: user,
challenge: gCredentialChallenge,
parameters: [param],
excludeList: [{type: "public-key", id: Uint8Array.from(aCredInfo.rawId),
transports: ["usb"]}]
};
credm.create({publicKey: makeCredentialOptions})
.then(function() {
// We should have errored here!
ok(false, "The excludeList didn't stop a duplicate being created!");

Просмотреть файл

@ -16,179 +16,233 @@
<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";
"use strict";
// Execute the full-scope test
SimpleTest.waitForExplicitFinish();
// Execute the full-scope test
SimpleTest.waitForExplicitFinish();
function arrivingHereIsGood(aResult) {
ok(true, "Good result! Received a: " + aResult);
return Promise.resolve();
}
function arrivingHereIsGood(aResult) {
ok(true, "Good result! Received a: " + aResult);
return Promise.resolve();
}
function arrivingHereIsBad(aResult) {
ok(false, "Bad result! Received a: " + aResult);
return Promise.resolve();
}
function arrivingHereIsBad(aResult) {
ok(false, "Bad result! Received a: " + aResult);
return Promise.resolve();
}
function expectNotAllowedError(aResult) {
ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
return Promise.resolve();
}
function expectNotAllowedError(aResult) {
ok(aResult.toString().startsWith("NotAllowedError"), "Expecting a NotAllowedError");
return Promise.resolve();
}
function expectTypeError(aResult) {
ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
return Promise.resolve();
}
function expectTypeError(aResult) {
ok(aResult.toString().startsWith("TypeError"), "Expecting a TypeError");
return Promise.resolve();
}
function expectNotSupportedError(aResult) {
ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
return Promise.resolve();
}
function expectNotSupportedError(aResult) {
ok(aResult.toString().startsWith("NotSupportedError"), "Expecting a NotSupportedError");
return Promise.resolve();
}
SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
["security.webauth.webauthn_enable_softtoken", true],
["security.webauth.webauthn_enable_usbtoken", false]]}, runTests);
function runTests() {
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
["security.webauth.webauthn_enable_softtoken", true],
["security.webauth.webauthn_enable_usbtoken", false]]}, runTests);
function runTests() {
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
let authn = navigator.authentication;
let authn = navigator.authentication;
let credm = navigator.credentials;
let gCredentialChallenge = new Uint8Array(16);
window.crypto.getRandomValues(gCredentialChallenge);
let gCredentialChallenge = new Uint8Array(16);
window.crypto.getRandomValues(gCredentialChallenge);
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
let param = {type: "ScopedCred", algorithm: "p-256"};
let unsupportedParam = {type: "ScopedCred", algorithm: "3DES"};
let badParam = {type: "SimplePassword", algorithm: "MaxLength=2"};
let rp = {id: "none", name: "none", icon: "none"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "p-256"};
let unsupportedParam = {type: "public-key", algorithm: "3DES"};
let badParam = {type: "SimplePassword", algorithm: "MaxLength=2"};
var testFuncs = [
// Test basic good call
function() {
return authn.makeCredential(acct, [param], gCredentialChallenge)
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
var testFuncs = [
// Test basic good call
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
// Test empty account
function() {
return authn.makeCredential({}, [param], gCredentialChallenge)
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test empty account
function() {
let makeCredentialOptions = {
challenge: gCredentialChallenge, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test without a parameter
function() {
return authn.makeCredential(acct, [], gCredentialChallenge)
.then(arrivingHereIsBad)
.catch(expectNotSupportedError);
},
// Test without a parameter
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge, parameters: []
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectNotSupportedError);
},
// Test without a parameter array at all
function() {
return authn.makeCredential(acct, null, gCredentialChallenge)
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test without a parameter array at all
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with an unsupported parameter
function() {
return authn.makeCredential(acct, [unsupportedParam], gCredentialChallenge)
.then(arrivingHereIsBad)
.catch(expectNotSupportedError);
},
// Test with an unsupported parameter
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge, parameters: [unsupportedParam]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectNotSupportedError);
},
// Test with an unsupported parameter and a good one
function() {
return authn.makeCredential(acct, [unsupportedParam, param], gCredentialChallenge)
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
// Test with an unsupported parameter and a good one
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge,
parameters: [param, unsupportedParam]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
// Test with a bad parameter
function() {
return authn.makeCredential(acct, [badParam], gCredentialChallenge)
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with a bad parameter
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge, parameters: [badParam]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with an unsupported parameter, and a bad one
function() {
return authn.makeCredential(acct, [unsupportedParam, badParam],
gCredentialChallenge)
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with an unsupported parameter, and a bad one
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge,
parameters: [unsupportedParam, badParam]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with an unsupported parameter, a bad one, and a good one. This
// should still fail, as anything with a badParam should fail.
function() {
return authn.makeCredential(acct, [unsupportedParam, badParam, param],
gCredentialChallenge)
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with an unsupported parameter, a bad one, and a good one. This
// should still fail, as anything with a badParam should fail.
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge,
parameters: [param, unsupportedParam, badParam]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test without a challenge
function() {
return authn.makeCredential(acct, [param], null)
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test without a challenge
function() {
let makeCredentialOptions = {
rp: rp, user: user, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with an invalid challenge
function() {
return authn.makeCredential(acct, [param], "begone, thou ill-fitting moist glove!")
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with an invalid challenge
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: "begone, thou ill-fitting moist glove!",
parameters: [unsupportedParam]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with duplicate parameters
function() {
return authn.makeCredential(acct, [param, param, param], gCredentialChallenge)
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
// Test with duplicate parameters
function() {
let makeCredentialOptions = {
rp: rp, user: user, challenge: gCredentialChallenge,
parameters: [param, param, param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
// Test an incomplete account
function() {
return authn.makeCredential({id: "none"
}, [param], gCredentialChallenge)
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with missing rp
function() {
let makeCredentialOptions = {
user: user, challenge: gCredentialChallenge, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
function() {
return authn.makeCredential({name: "none", imageURL: "http://example.com/404"},
[param], gCredentialChallenge)
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test with missing user
function() {
let makeCredentialOptions = {
rp: rp, challenge: gCredentialChallenge, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectTypeError);
},
// Test a complete account
function() {
return authn.makeCredential({rpDisplayName: "Foxxy", displayName: "Foxxy V",
id: "foxes_are_the_best@example.com",
name: "Fox F. Foxington",
imageURL: "https://example.com/fox.svg"},
[param], gCredentialChallenge)
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
}];
// Test a complete account
function() {
let completeRP = {id: "Foxxy RP", name: "Foxxy Name",
icon: "https://example.com/fox.svg"};
let completeUser = {id: "foxes_are_the_best@example.com",
name: "Fox F. Foxington",
icon: "https://example.com/fox.svg",
displayName: "Foxxy V"};
let makeCredentialOptions = {
rp: completeRP, user: completeUser, challenge: gCredentialChallenge,
parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
}];
var i = 0;
var runNextTest = () => {
if (i == testFuncs.length) {
SimpleTest.finish();
return;
}
testFuncs[i]().then(() => { runNextTest(); });
i = i + 1;
};
runNextTest();
};
var i = 0;
var runNextTest = () => {
if (i == testFuncs.length) {
SimpleTest.finish();
return;
}
testFuncs[i]().then(() => { runNextTest(); });
i = i + 1;
};
runNextTest();
};
</script>

Просмотреть файл

@ -27,10 +27,13 @@ SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
["security.webauth.webauthn_enable_usbtoken", false]]},
function() {
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
isnot(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint must exist");
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
let authn = navigator.authentication;
let credm = navigator.credentials;
let credentialChallenge = new Uint8Array(16);
window.crypto.getRandomValues(credentialChallenge);
@ -42,9 +45,13 @@ function() {
testMakeCredential();
function testMakeCredential() {
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
let param = {type: "ScopedCred", algorithm: "p-256"};
authn.makeCredential(acct, [param], credentialChallenge)
let rp = {id: "none", name: "none", icon: "none"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "p-256"};
let makeCredentialOptions = {
rp: rp, user: user, challenge: credentialChallenge, parameters: [param]
};
credm.create({publicKey: makeCredentialOptions})
.then(function(aResult) {
ok(false, "Should have failed.");
testAssertion();
@ -59,10 +66,10 @@ function() {
let newCredential = {
type: "ScopedCred",
id: credentialId,
transports: [ "usb" ],
transports: ["usb"],
}
let assertOptions = {rpId: document.origin, timeoutSeconds: 5,
allowList: [ newCredential ]};
allowList: [newCredential]};
authn.getAssertion(assertionChallenge, assertOptions)
.then(function(aResult) {
ok(false, "Should have failed.");

Просмотреть файл

@ -16,169 +16,195 @@
<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";
"use strict";
// Execute the full-scope test
SimpleTest.waitForExplicitFinish();
// Execute the full-scope test
SimpleTest.waitForExplicitFinish();
var gTrackedCredential = {};
var gTrackedCredential = {};
function arrivingHereIsGood(aResult) {
ok(true, "Good result! Received a: " + aResult);
return Promise.resolve();
}
function arrivingHereIsGood(aResult) {
ok(true, "Good result! Received a: " + aResult);
return Promise.resolve();
}
function arrivingHereIsBad(aResult) {
// TODO: Change to `ok` when Bug 1329764 lands
todo(false, "Bad result! Received a: " + aResult);
return Promise.resolve();
}
function arrivingHereIsBad(aResult) {
// TODO: Change to `ok` when Bug 1329764 lands
todo(false, "Bad result! Received a: " + aResult);
return Promise.resolve();
}
function expectSecurityError(aResult) {
// TODO: Change to `ok` when Bug 1329764 lands
todo(aResult.toString().startsWith("SecurityError"), "Expecting a SecurityError");
return Promise.resolve();
}
function expectSecurityError(aResult) {
// TODO: Change to `ok` when Bug 1329764 lands
todo(aResult.toString().startsWith("SecurityError"), "Expecting a SecurityError");
return Promise.resolve();
}
function keepThisPublicKeyCredential(aPublicKeyCredential) {
gTrackedCredential = {
type: "ScopedCred",
id: Uint8Array.from(aPublicKeyCredential.rawId),
transports: [ "usb" ],
}
return Promise.resolve(aPublicKeyCredential);
}
function keepThisPublicKeyCredential(aPublicKeyCredential) {
gTrackedCredential = {
type: "ScopedCred",
id: Uint8Array.from(aPublicKeyCredential.rawId),
transports: [ "usb" ],
}
return Promise.resolve(aPublicKeyCredential);
}
function runTests() {
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
isnot(navigator.authentication.makeCredential, undefined,
"WebAuthn makeCredential API endpoint must exist");
isnot(navigator.authentication.getAssertion, undefined,
"WebAuthn getAssertion API endpoint must exist");
function runTests() {
isnot(navigator.authentication, undefined, "WebAuthn API endpoint must exist");
isnot(navigator.credentials, undefined, "Credential Management API endpoint must exist");
is(navigator.authentication.makeCredential, undefined, "WebAuthn makeCredential API endpoint does not exist any longer");
isnot(navigator.authentication.getAssertion, undefined, "WebAuthn getAssertion API endpoint must exist");
isnot(navigator.credentials.create, undefined, "CredentialManagement create API endpoint must exist");
let authn = navigator.authentication;
let authn = navigator.authentication;
let credm = navigator.credentials;
let chall = new Uint8Array(16);
window.crypto.getRandomValues(chall);
let chall = new Uint8Array(16);
window.crypto.getRandomValues(chall);
let acct = {rpDisplayName: "none", displayName: "none", id: "none"};
let param = {type: "ScopedCred", algorithm: "p-256"};
let user = {id: "none", name: "none", icon: "none", displayName: "none"};
let param = {type: "public-key", algorithm: "p-256"};
var testFuncs = [
function() {
// Test basic good call
return authn.makeCredential(acct, [param], chall, {rpId: document.origin})
.then(keepThisPublicKeyCredential)
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
var testFuncs = [
function() {
// Test basic good call
let rp = {id: document.origin};
let makeCredentialOptions = {
rp: rp, user: user, challenge: chall, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(keepThisPublicKeyCredential)
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
function() {
// Test rpId being unset
return authn.makeCredential(acct, [param], chall, {})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
function() {
// Test this origin with optional fields
return authn.makeCredential(acct, [param], chall,
{rpId: "user:pass@" + document.origin + ":8888"})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function() {
// Test blank rpId
return authn.makeCredential(acct, [param], chall, {rpId: ""})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function() {
// Test subdomain of this origin
return authn.makeCredential(acct, [param], chall,
{rpId: "subdomain." + document.origin})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function() {
// Test another origin
return authn.makeCredential(acct, [param], chall, {rpId: "example.com"})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// est a different domain within the same TLD
return authn.makeCredential(acct, [param], chall, {rpId: "alt.test"})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test basic good call
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
rpId: document.origin})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
function () {
// Test rpId being unset
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ]})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
function () {
// Test this origin with optional fields
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
rpId: "user:pass@" + document.origin + ":8888"})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test blank rpId
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
rpId: ""})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test subdomain of this origin
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
rpId: "subdomain." + document.origin})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test another origin
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
rpId: "example.com"})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test a different domain within the same TLD
return authn.getAssertion(chall, {allowList: [ gTrackedCredential ],
rpId: "alt.test"})
.then(arrivingHereIsBad)
.catch(expectSecurityError)
},
function () {
SimpleTest.finish();
}
];
var i = 0;
var runNextTest = () => {
if (i == testFuncs.length) {
SimpleTest.finish();
return;
}
console.log(i);
testFuncs[i]().then(() => { runNextTest(); });
i = i + 1;
};
runNextTest();
};
SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
["security.webauth.webauthn_enable_softtoken", true],
["security.webauth.webauthn_enable_usbtoken", false]]},
runTests);
function() {
// Test rp.id being unset
let makeCredentialOptions = {
rp: {}, user: user, challenge: chall, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
function() {
// Test this origin with optional fields
let rp = {id: "user:pass@" + document.origin + ":8888"};
let makeCredentialOptions = {
rp: rp, user: user, challenge: chall, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function() {
// Test blank rp.id
let rp = {id: ""};
let makeCredentialOptions = {
rp: rp, user: user, challenge: chall, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function() {
// Test subdomain of this origin
let rp = {id: "subdomain." + document.origin};
let makeCredentialOptions = {
rp: rp, user: user, challenge: chall, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function() {
// Test another origin
let rp = {id: "example.com"};
let makeCredentialOptions = {
rp: rp, user: user, challenge: chall, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test a different domain within the same TLD
let rp = {id: "alt.test"};
let makeCredentialOptions = {
rp: rp, user: user, challenge: chall, parameters: [param]
};
return credm.create({publicKey: makeCredentialOptions})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test basic good call
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
rpId: document.origin})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
function () {
// Test rpId being unset
return authn.getAssertion(chall, {allowList: [gTrackedCredential]})
.then(arrivingHereIsGood)
.catch(arrivingHereIsBad);
},
function () {
// Test this origin with optional fields
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
rpId: "user:pass@" + document.origin + ":8888"})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test blank rpId
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
rpId: ""})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test subdomain of this origin
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
rpId: "subdomain." + document.origin})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test another origin
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
rpId: "example.com"})
.then(arrivingHereIsBad)
.catch(expectSecurityError);
},
function () {
// Test a different domain within the same TLD
return authn.getAssertion(chall, {allowList: [gTrackedCredential],
rpId: "alt.test"})
.then(arrivingHereIsBad)
.catch(expectSecurityError)
},
function () {
SimpleTest.finish();
}
];
var i = 0;
var runNextTest = () => {
if (i == testFuncs.length) {
SimpleTest.finish();
return;
}
console.log(i);
testFuncs[i]().then(() => { runNextTest(); });
i = i + 1;
};
runNextTest();
};
SpecialPowers.pushPrefEnv({"set": [["security.webauth.webauthn", true],
["security.webauth.webauthn_enable_softtoken", true],
["security.webauth.webauthn_enable_usbtoken", false]]},
runTests);
</script>

Просмотреть файл

@ -12,3 +12,12 @@ interface Credential {
readonly attribute USVString id;
readonly attribute DOMString type;
};
[Exposed=Window, SecureContext, Pref="security.webauth.webauthn"]
interface CredentialsContainer {
Promise<Credential?> create(optional CredentialCreationOptions options);
};
dictionary CredentialCreationOptions {
MakeCredentialOptions publicKey;
};

Просмотреть файл

@ -373,3 +373,8 @@ partial interface Navigator {
[Pref="security.webauth.webauthn", SameObject]
readonly attribute WebAuthentication authentication;
};
partial interface Navigator {
[Pref="security.webauth.webauthn", SameObject]
readonly attribute CredentialsContainer credentials;
};

Просмотреть файл

@ -27,28 +27,67 @@ interface AuthenticatorAttestationResponse : AuthenticatorResponse {
readonly attribute ArrayBuffer attestationObject;
};
dictionary Account {
required DOMString rpDisplayName;
required DOMString displayName;
required DOMString id;
DOMString name;
DOMString imageURL;
dictionary PublicKeyCredentialParameters {
required PublicKeyCredentialType type;
required WebAuthnAlgorithmID algorithm; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
};
dictionary PublicKeyCredentialUserEntity : PublicKeyCredentialEntity {
DOMString displayName;
};
dictionary MakeCredentialOptions {
required PublicKeyCredentialEntity rp;
required PublicKeyCredentialUserEntity user;
required BufferSource challenge;
required sequence<PublicKeyCredentialParameters> parameters;
unsigned long timeout;
sequence<PublicKeyCredentialDescriptor> excludeList;
AuthenticatorSelectionCriteria authenticatorSelection;
// Extensions are not supported yet.
// AuthenticationExtensions extensions;
};
dictionary PublicKeyCredentialEntity {
DOMString id;
DOMString name;
USVString icon;
};
dictionary AuthenticatorSelectionCriteria {
Attachment attachment;
boolean requireResidentKey = false;
};
enum Attachment {
"platform",
"cross-platform"
};
dictionary CollectedClientData {
required DOMString challenge;
required DOMString origin;
required DOMString hashAlg;
DOMString tokenBinding;
// Extensions are not supported yet.
// AuthenticationExtensions clientExtensions;
// AuthenticationExtensions authenticatorExtensions;
};
enum PublicKeyCredentialType {
"public-key"
};
dictionary PublicKeyCredentialDescriptor {
required PublicKeyCredentialType type;
required BufferSource id;
sequence<WebAuthnTransport> transports;
};
typedef (boolean or DOMString) WebAuthnAlgorithmID; // Fix when upstream there's a definition of how to serialize AlgorithmIdentifier
dictionary ScopedCredentialParameters {
required ScopedCredentialType type;
required WebAuthnAlgorithmID algorithm; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
};
dictionary ScopedCredentialOptions {
unsigned long timeoutSeconds;
USVString rpId;
sequence<ScopedCredentialDescriptor> excludeList;
WebAuthnExtensions extensions;
};
[SecureContext, Pref="security.webauth.webauthn"]
interface AuthenticatorAssertionResponse : AuthenticatorResponse {
readonly attribute ArrayBuffer authenticatorData;
@ -65,25 +104,10 @@ dictionary AssertionOptions {
dictionary WebAuthnExtensions {
};
// Renamed from "ClientData" to avoid a collision with U2F
dictionary WebAuthnClientData {
required DOMString challenge;
required DOMString origin;
required WebAuthnAlgorithmID hashAlg; // NOTE: changed from AllgorithmIdentifier because typedef (object or DOMString) not serializable
DOMString tokenBinding;
WebAuthnExtensions extensions;
};
enum ScopedCredentialType {
"ScopedCred"
};
[SecureContext, Pref="security.webauth.webauthn"]
interface ScopedCredential {
readonly attribute ScopedCredentialType type;
readonly attribute ArrayBuffer id;
};
dictionary ScopedCredentialDescriptor {
required ScopedCredentialType type;
required BufferSource id;
@ -101,13 +125,6 @@ enum WebAuthnTransport {
[SecureContext, Pref="security.webauth.webauthn"]
interface WebAuthentication {
Promise<PublicKeyCredential> makeCredential (
Account accountInformation,
sequence<ScopedCredentialParameters> cryptoParameters,
BufferSource attestationChallenge,
optional ScopedCredentialOptions options
);
Promise<PublicKeyCredential> getAssertion (
BufferSource assertionChallenge,
optional AssertionOptions options