Bug 1892010 - Redefine the IdentityCredential to support the lightweight version, r=anti-tracking-reviewers,webidl,smaug,timhuang,geckoview-reviewers,owlish

Prototyping https://github.com/fedidcg/CrossSiteCookieAccessCredential.

There is no change here in even Nightly behavior- keeping everything behind a pref.

Differential Revision: https://phabricator.services.mozilla.com/D209828
This commit is contained in:
Benjamin VanderSloot 2024-06-05 18:04:33 +00:00
Родитель 6d5d7fe17d
Коммит 5562014f59
12 изменённых файлов: 245 добавлений и 120 удалений

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

@ -3025,6 +3025,7 @@ pref("cookiebanners.ui.desktop.cfrVariant", 0);
#ifdef NIGHTLY_BUILD
pref("dom.security.credentialmanagement.identity.enabled", true);
pref("dom.security.credentialmanagement.identity.heavyweight.enabled", true);
#endif
pref("ui.new-webcompat-reporter.enabled", true);

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

@ -4,14 +4,22 @@
* 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/PermissionMessageUtils.h";
[RefCounted] using class nsIPrincipal from "nsIPrincipal.h";
namespace mozilla {
namespace dom {
struct IPCIdentityCredential
{
nsString id;
nsString type;
nsString token;
nsString? token;
nsCString? name;
nsCString? iconURL;
nsCString[] originAllowlist;
nsCString? dynamicViaCors;
nsCString? infoExpires;
nullable nsIPrincipal identityProvider;
};
}

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

@ -37,26 +37,106 @@ JSObject* IdentityCredential::WrapObject(JSContext* aCx,
}
IdentityCredential::IdentityCredential(nsPIDOMWindowInner* aParent)
: Credential(aParent) {}
void IdentityCredential::CopyValuesFrom(const IPCIdentityCredential& aOther) {
this->SetToken(aOther.token());
this->SetId(aOther.id());
this->SetType(aOther.type());
: Credential(aParent) {
if (aParent && aParent->GetBrowsingContext() &&
aParent->GetBrowsingContext()->Top() &&
aParent->GetBrowsingContext()->Top()->GetDocument()) {
this->mIdentityProvider =
aParent->GetBrowsingContext()->Top()->GetDocument()->GetPrincipal();
}
}
IPCIdentityCredential IdentityCredential::MakeIPCIdentityCredential() {
nsString token, id, type;
GetToken(token);
GetId(id);
GetType(type);
IdentityCredential::IdentityCredential(nsPIDOMWindowInner* aParent,
const IPCIdentityCredential& aOther)
: Credential(aParent) {
CopyValuesFrom(aOther);
}
void IdentityCredential::CopyValuesFrom(const IPCIdentityCredential& aOther) {
this->SetId(aOther.id());
this->SetType(u"identity"_ns);
if (aOther.token().isSome()) {
this->SetToken(aOther.token().value());
}
IdentityCredentialInit creationOptions;
if (aOther.dynamicViaCors().isSome()) {
creationOptions.mDynamicViaCORS.Construct(aOther.dynamicViaCors().value());
}
if (aOther.originAllowlist().Length() > 0) {
creationOptions.mOriginAllowlist.Construct(
Sequence(aOther.originAllowlist().Clone()));
}
creationOptions.mId = aOther.id();
IdentityCredentialUserData userData;
if (aOther.name().isSome()) {
userData.mName = aOther.name()->Data();
}
if (aOther.iconURL().isSome()) {
userData.mIconURL = aOther.iconURL()->Data();
}
if (aOther.infoExpires().isSome()) {
userData.mExpires.Construct(aOther.infoExpires()->get());
}
if (aOther.name().isSome() || aOther.iconURL().isSome() ||
aOther.infoExpires().isSome()) {
creationOptions.mUiHint.Construct(userData);
}
this->mCreationOptions = Some(creationOptions);
this->mIdentityProvider = aOther.identityProvider();
}
IPCIdentityCredential IdentityCredential::MakeIPCIdentityCredential() const {
IPCIdentityCredential result;
result.token() = token;
result.id() = id;
result.type() = type;
result.identityProvider() = mIdentityProvider;
this->GetId(result.id());
if (!this->mToken.IsEmpty()) {
result.token() = Some(this->mToken);
}
if (this->mCreationOptions.isSome()) {
if (this->mCreationOptions->mDynamicViaCORS.WasPassed()) {
result.dynamicViaCors() =
Some(this->mCreationOptions->mDynamicViaCORS.Value());
}
if (this->mCreationOptions->mOriginAllowlist.WasPassed()) {
result.originAllowlist() =
this->mCreationOptions->mOriginAllowlist.Value();
}
if (this->mCreationOptions->mUiHint.WasPassed() &&
!this->mCreationOptions->mUiHint.Value().mIconURL.IsEmpty()) {
result.iconURL() = Some(this->mCreationOptions->mUiHint.Value().mIconURL);
}
if (this->mCreationOptions->mUiHint.WasPassed() &&
!this->mCreationOptions->mUiHint.Value().mName.IsEmpty()) {
result.name() = Some(this->mCreationOptions->mUiHint.Value().mName);
}
if (this->mCreationOptions->mUiHint.WasPassed() &&
this->mCreationOptions->mUiHint.Value().mExpires.WasPassed()) {
result.infoExpires() =
Some(this->mCreationOptions->mUiHint.Value().mExpires.Value());
}
}
return result;
}
// static
already_AddRefed<IdentityCredential> IdentityCredential::Constructor(
const GlobalObject& aGlobal, const IdentityCredentialInit& aInit,
ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
if (!global || !global->GetAsInnerWindow() || !global->PrincipalOrNull()) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
RefPtr<IdentityCredential> result =
new IdentityCredential(global->GetAsInnerWindow());
result->SetId(aInit.mId);
result->SetType(u"identity"_ns);
result->mCreationOptions.emplace(aInit);
result->mIdentityProvider = global->PrincipalOrNull();
return result.forget();
}
void IdentityCredential::GetToken(nsAString& aToken) const {
aToken.Assign(mToken);
}
@ -64,6 +144,16 @@ void IdentityCredential::SetToken(const nsAString& aToken) {
mToken.Assign(aToken);
}
void IdentityCredential::GetOrigin(nsACString& aOrigin,
ErrorResult& aError) const {
nsresult rv = mIdentityProvider->GetWebExposedOriginSerialization(aOrigin);
if (NS_FAILED(rv)) {
aOrigin.SetLength(0);
aError.Throw(rv);
}
}
// static
RefPtr<IdentityCredential::GetIdentityCredentialPromise>
IdentityCredential::DiscoverFromExternalSource(
@ -130,6 +220,19 @@ IdentityCredential::DiscoverFromExternalSourceInMainProcess(
NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
}
// Make sure we support the set of features needed for this request
RequestType requestType = DetermineRequestType(aOptions);
if ((!StaticPrefs::
dom_security_credentialmanagement_identity_heavyweight_enabled() &&
requestType == HEAVYWEIGHT) ||
(!StaticPrefs::
dom_security_credentialmanagement_identity_lightweight_enabled() &&
requestType == LIGHTWEIGHT) ||
requestType == INVALID) {
return IdentityCredential::GetIPCIdentityCredentialPromise::CreateAndReject(
NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
}
RefPtr<IdentityCredential::GetIPCIdentityCredentialPromise::Private> result =
new IdentityCredential::GetIPCIdentityCredentialPromise::Private(
__func__);
@ -214,7 +317,8 @@ IdentityCredential::DiscoverFromExternalSourceInMainProcess(
IdentityProviderAPIConfig manifest;
IdentityProviderConfig provider;
std::tie(provider, manifest) = providerAndManifest;
return IdentityCredential::CreateCredential(
return IdentityCredential::
CreateHeavyweightCredentialDuringDiscovery(
principal, browsingContext, provider, manifest);
},
[](nsresult error) {
@ -243,7 +347,7 @@ IdentityCredential::DiscoverFromExternalSourceInMainProcess(
// static
RefPtr<IdentityCredential::GetIPCIdentityCredentialPromise>
IdentityCredential::CreateCredential(
IdentityCredential::CreateHeavyweightCredentialDuringDiscovery(
nsIPrincipal* aPrincipal, BrowsingContext* aBrowsingContext,
const IdentityProviderConfig& aProvider,
const IdentityProviderAPIConfig& aManifest) {
@ -316,9 +420,8 @@ IdentityCredential::CreateCredential(
IdentityProviderAccount account;
std::tie(token, account) = promiseResult;
IPCIdentityCredential credential;
credential.token() = token.mToken;
credential.token() = Some(token.mToken);
credential.id() = account.mId;
credential.type() = u"identity"_ns;
return IdentityCredential::GetIPCIdentityCredentialPromise::
CreateAndResolve(credential, __func__);
},
@ -342,7 +445,7 @@ IdentityCredential::CheckRootManifest(nsIPrincipal* aPrincipal,
}
// Build the URL
nsCString configLocation = aProvider.mConfigURL;
nsCString configLocation = aProvider.mConfigURL.Value();
nsCOMPtr<nsIURI> configURI;
nsresult rv = NS_NewURI(getter_AddRefs(configURI), configLocation);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -407,7 +510,8 @@ IdentityCredential::CheckRootManifest(nsIPrincipal* aPrincipal,
// Resolve whether or not that provider URL is the one we were
// passed as an argument.
bool correctURL = manifest.mProvider_urls[0] == aProvider.mConfigURL;
bool correctURL =
manifest.mProvider_urls[0] == aProvider.mConfigURL.Value();
return IdentityCredential::ValidationPromise::CreateAndResolve(
correctURL, __func__);
},
@ -423,7 +527,7 @@ IdentityCredential::FetchInternalManifest(
nsIPrincipal* aPrincipal, const IdentityProviderConfig& aProvider) {
MOZ_ASSERT(XRE_IsParentProcess());
// Build the URL
nsCString configLocation = aProvider.mConfigURL;
nsCString configLocation = aProvider.mConfigURL.Value();
// Create the global
RefPtr<NullPrincipal> nullPrincipal =
@ -472,7 +576,8 @@ IdentityCredential::FetchAccountList(
MOZ_ASSERT(XRE_IsParentProcess());
// Build the URL
nsCOMPtr<nsIURI> baseURI;
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), aProvider.mConfigURL);
nsresult rv =
NS_NewURI(getter_AddRefs(baseURI), aProvider.mConfigURL.Value());
if (NS_WARN_IF(NS_FAILED(rv))) {
return IdentityCredential::GetAccountListPromise::CreateAndReject(rv,
__func__);
@ -560,7 +665,7 @@ RefPtr<IdentityCredential::GetTokenPromise> IdentityCredential::FetchToken(
MOZ_ASSERT(XRE_IsParentProcess());
// Build the URL
nsCOMPtr<nsIURI> baseURI;
nsCString baseURIString = aProvider.mConfigURL;
nsCString baseURIString = aProvider.mConfigURL.Value();
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), baseURIString);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IdentityCredential::GetTokenPromise::CreateAndReject(rv, __func__);
@ -603,7 +708,7 @@ RefPtr<IdentityCredential::GetTokenPromise> IdentityCredential::FetchToken(
internalRequest->SetMethod("POST"_ns);
URLParams bodyValue;
bodyValue.Set("account_id"_ns, NS_ConvertUTF16toUTF8(aAccount.mId));
bodyValue.Set("client_id"_ns, aProvider.mClientId);
bodyValue.Set("client_id"_ns, aProvider.mClientId.Value());
if (aProvider.mNonce.WasPassed()) {
bodyValue.Set("nonce"_ns, aProvider.mNonce.Value());
}
@ -658,7 +763,7 @@ IdentityCredential::FetchMetadata(nsIPrincipal* aPrincipal,
MOZ_ASSERT(aPrincipal);
// Build the URL
nsCOMPtr<nsIURI> baseURI;
nsCString baseURIString = aProvider.mConfigURL;
nsCString baseURIString = aProvider.mConfigURL.Value();
nsresult rv = NS_NewURI(getter_AddRefs(baseURI), baseURIString);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IdentityCredential::GetMetadataPromise::CreateAndReject(rv,
@ -914,7 +1019,7 @@ IdentityCredential::PromptUserWithPolicy(
}
// Check the storage bit
nsCString configLocation = aProvider.mConfigURL;
nsCString configLocation = aProvider.mConfigURL.Value();
nsCOMPtr<nsIURI> idpURI;
error = NS_NewURI(getter_AddRefs(idpURI), configLocation);
if (NS_WARN_IF(NS_FAILED(error))) {
@ -1048,66 +1153,20 @@ void IdentityCredential::CloseUserInterface(BrowsingContext* aBrowsingContext) {
}
// static
already_AddRefed<Promise> IdentityCredential::LogoutRPs(
GlobalObject& aGlobal,
const Sequence<IdentityCredentialLogoutRPsRequest>& aLogoutRequests,
ErrorResult& aRv) {
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<Promise> promise = Promise::CreateResolvedWithUndefined(global, aRv);
NS_ENSURE_FALSE(aRv.Failed(), nullptr);
nsresult rv;
nsCOMPtr<nsIIdentityCredentialStorageService> icStorageService =
components::IdentityCredentialStorageService::Service(&rv);
if (NS_WARN_IF(!icStorageService)) {
aRv.Throw(rv);
return nullptr;
IdentityCredential::RequestType IdentityCredential::DetermineRequestType(
const IdentityCredentialRequestOptions& aOptions) {
if (!aOptions.mProviders.WasPassed()) {
return INVALID;
}
RefPtr<nsIPrincipal> rpPrincipal = global->PrincipalOrNull();
for (const auto& request : aLogoutRequests) {
// Get the current state
nsCOMPtr<nsIURI> idpURI;
rv = NS_NewURI(getter_AddRefs(idpURI), request.mUrl);
if (NS_FAILED(rv)) {
aRv.ThrowTypeError<MSG_INVALID_URL>(request.mUrl);
return nullptr;
for (const IdentityProviderConfig& provider : aOptions.mProviders.Value()) {
if (provider.mConfigURL.WasPassed()) {
return HEAVYWEIGHT;
}
nsCOMPtr<nsIPrincipal> idpPrincipal = BasePrincipal::CreateContentPrincipal(
idpURI, rpPrincipal->OriginAttributesRef());
bool registered, allowLogout;
icStorageService->GetState(rpPrincipal, idpPrincipal, request.mAccountId,
&registered, &allowLogout);
// Ignore this request if it isn't permitted
if (!(registered && allowLogout)) {
continue;
if (!provider.mOrigin.WasPassed() && !provider.mLoginURL.WasPassed()) {
return INVALID;
}
// Issue the logout request
constexpr auto fragment = ""_ns;
auto internalRequest =
MakeSafeRefPtr<InternalRequest>(request.mUrl, fragment);
internalRequest->SetRedirectMode(RequestRedirect::Error);
internalRequest->SetCredentialsMode(RequestCredentials::Include);
internalRequest->SetReferrerPolicy(ReferrerPolicy::Strict_origin);
internalRequest->SetMode(RequestMode::Cors);
internalRequest->SetCacheMode(RequestCache::No_cache);
internalRequest->OverrideContentPolicyType(
nsContentPolicyType::TYPE_WEB_IDENTITY);
RefPtr<Request> domRequest =
new Request(global, std::move(internalRequest), nullptr);
RequestOrUTF8String fetchInput;
fetchInput.SetAsRequest() = domRequest;
RootedDictionary<RequestInit> requestInit(RootingCx());
IgnoredErrorResult error;
RefPtr<Promise> fetchPromise = FetchRequest(global, fetchInput, requestInit,
CallerType::System, error);
// Change state to disallow more logout requests
icStorageService->SetState(rpPrincipal, idpPrincipal, request.mAccountId,
true, false);
}
return promise.forget();
return LIGHTWEIGHT;
}
} // namespace mozilla::dom

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

@ -10,6 +10,7 @@
#include "mozilla/dom/CanonicalBrowsingContext.h"
#include "mozilla/dom/Credential.h"
#include "mozilla/dom/IPCIdentityCredential.h"
#include "mozilla/IdentityCredentialStorageService.h"
#include "mozilla/MozPromise.h"
namespace mozilla::dom {
@ -20,6 +21,8 @@ namespace mozilla::dom {
// with an "identity" argument. It also includes static functions that
// perform operations that are used in constructing the credential.
class IdentityCredential final : public Credential {
friend class mozilla::IdentityCredentialStorageService;
public:
// These are promise types, all used to support the async implementation of
// this API. All are of the form MozPromise<RefPtr<T>, nsresult>.
@ -53,12 +56,18 @@ class IdentityCredential final : public Credential {
typedef MozPromise<IdentityProviderClientMetadata, nsresult, true>
GetMetadataPromise;
// This needs to be constructed in the context of a window
explicit IdentityCredential(nsPIDOMWindowInner* aParent);
protected:
~IdentityCredential() override;
// This needs to be constructed in the context of a window
// This is called in the context of Create and Constructor. aParent is the
// identity provider
explicit IdentityCredential(nsPIDOMWindowInner* aParent);
// This is called in the context of Discover and Collect. the identity
// provider is in aOther
explicit IdentityCredential(nsPIDOMWindowInner* aParent,
const IPCIdentityCredential& aOther);
public:
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
@ -70,31 +79,18 @@ class IdentityCredential final : public Credential {
void CopyValuesFrom(const IPCIdentityCredential& aOther);
// This is the inverse of CopyValuesFrom. Included for completeness.
IPCIdentityCredential MakeIPCIdentityCredential();
IPCIdentityCredential MakeIPCIdentityCredential() const;
static already_AddRefed<IdentityCredential> Constructor(
const GlobalObject& aGlobal, const IdentityCredentialInit& aInit,
ErrorResult& aRv);
// Getter and setter for the token member of this class
void GetToken(nsAString& aToken) const;
void SetToken(const nsAString& aToken);
// This function allows a relying party to send one last credentialed request
// to the IDP when logging out. This only works if the current account state
// in the IdentityCredentialStorageService allows logouts and clears that bit
// when a request is sent.
//
// Arguments:
// aGlobal: the global of the window calling this function
// aLogoutRequest: all of the logout requests to try to send.
// This is pairs of the IDP's logout url and the account
// ID for that IDP.
// Return value:
// a promise resolving to undefined
// Side effects:
// Will send a network request to each IDP that have a state allowing
// logouts and disables that bit.
static already_AddRefed<Promise> LogoutRPs(
GlobalObject& aGlobal,
const Sequence<IdentityCredentialLogoutRPsRequest>& aLogoutRequests,
ErrorResult& aRv);
// Get the Origin of this credential's identity provider
void GetOrigin(nsACString& aOrigin, ErrorResult& aError) const;
// This is the main static function called when a credential needs to be
// fetched from the IDP. Called in the content process.
@ -138,7 +134,8 @@ class IdentityCredential final : public Credential {
// Side effects:
// Will send network requests to the IDP. The details of which are in the
// other static methods here.
static RefPtr<GetIPCIdentityCredentialPromise> CreateCredential(
static RefPtr<GetIPCIdentityCredentialPromise>
CreateHeavyweightCredentialDuringDiscovery(
nsIPrincipal* aPrincipal, BrowsingContext* aBrowsingContext,
const IdentityProviderConfig& aProvider,
const IdentityProviderAPIConfig& aManifest);
@ -307,6 +304,14 @@ class IdentityCredential final : public Credential {
private:
nsAutoString mToken;
nsCOMPtr<nsIPrincipal> mIdentityProvider;
Maybe<IdentityCredentialInit> mCreationOptions;
// Identity credential requests can either be heavyweight or lighweight in
// their browser UI. The heavyweight ones are "traditional" FedCM
enum RequestType { INVALID, LIGHTWEIGHT, HEAVYWEIGHT };
static RequestType DetermineRequestType(
const IdentityCredentialRequestOptions& aOptions);
};
} // namespace mozilla::dom

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

@ -20,12 +20,20 @@ struct ParamTraits<mozilla::dom::IdentityProviderConfig> {
WriteParam(aWriter, aParam.mConfigURL);
WriteParam(aWriter, aParam.mClientId);
WriteParam(aWriter, aParam.mNonce);
WriteParam(aWriter, aParam.mOrigin);
WriteParam(aWriter, aParam.mLoginURL);
WriteParam(aWriter, aParam.mLoginTarget);
WriteParam(aWriter, aParam.mDynamicViaCORS);
}
static bool Read(MessageReader* aReader, paramType* aResult) {
return ReadParam(aReader, &aResult->mConfigURL) &&
ReadParam(aReader, &aResult->mClientId) &&
ReadParam(aReader, &aResult->mNonce);
ReadParam(aReader, &aResult->mNonce) &&
ReadParam(aReader, &aResult->mOrigin) &&
ReadParam(aReader, &aResult->mLoginURL) &&
ReadParam(aReader, &aResult->mLoginTarget) &&
ReadParam(aReader, &aResult->mDynamicViaCORS);
}
};
@ -39,7 +47,6 @@ struct ParamTraits<mozilla::dom::IdentityCredentialRequestOptions> {
static bool Read(MessageReader* aReader, paramType* aResult) {
return ReadParam(aReader, &aResult->mProviders);
;
}
};

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

@ -1,6 +1,7 @@
[DEFAULT]
prefs = [
"dom.security.credentialmanagement.identity.enabled=true",
"dom.security.credentialmanagement.identity.heavyweight.enabled=true",
"dom.security.credentialmanagement.identity.ignore_well_known=true",
"privacy.antitracking.enableWebcompat=false", # disables opener heuristic
]

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

@ -1,6 +1,7 @@
[DEFAULT]
prefs = [
"dom.security.credentialmanagement.identity.enabled=true",
"dom.security.credentialmanagement.identity.heavyweight.enabled=true",
"dom.security.credentialmanagement.identity.select_first_in_ui_lists=true",
"dom.security.credentialmanagement.identity.reject_delay.enabled=false",
"privacy.antitracking.enableWebcompat=false", # disables opener heuristic

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

@ -54,5 +54,7 @@ dictionary CredentialCreationOptions {
// https://w3c.github.io/webauthn/#sctn-credentialcreationoptions-extension
[Pref="security.webauth.webauthn"]
PublicKeyCredentialCreationOptions publicKey;
[Pref="dom.security.credentialmanagement.identity.enabled"]
IdentityCredentialInit identity;
AbortSignal signal;
};

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

@ -12,8 +12,10 @@
Pref="dom.security.credentialmanagement.identity.enabled"]
interface IdentityCredential : Credential {
readonly attribute USVString? token;
[Throws]
static Promise<undefined> logoutRPs(sequence<IdentityCredentialLogoutRPsRequest> logoutRequests);
[Throws, Pref="dom.security.credentialmanagement.identity.lightweight.enabled"]
readonly attribute UTF8String origin;
[Throws, Pref="dom.security.credentialmanagement.identity.lightweight.enabled"]
constructor(IdentityCredentialInit init);
};
dictionary IdentityCredentialRequestOptions {
@ -22,11 +24,38 @@ dictionary IdentityCredentialRequestOptions {
[GenerateConversionToJS]
dictionary IdentityProviderConfig {
required UTF8String configURL;
required UTF8String clientId;
UTF8String configURL;
UTF8String clientId;
UTF8String nonce;
[Pref="dom.security.credentialmanagement.identity.lightweight.enabled"]
UTF8String origin;
[Pref="dom.security.credentialmanagement.identity.lightweight.enabled"]
UTF8String loginURL;
[Pref="dom.security.credentialmanagement.identity.lightweight.enabled"]
UTF8String loginTarget;
[Pref="dom.security.credentialmanagement.identity.lightweight.enabled"]
UTF8String dynamicViaCORS;
[Pref="dom.security.credentialmanagement.identity.lightweight.enabled"]
UTF8String data;
};
// Lightweight only
dictionary IdentityCredentialUserData {
required UTF8String name;
required UTF8String iconURL;
UTF8String expires;
};
dictionary IdentityCredentialInit {
required DOMString id;
sequence<UTF8String> originAllowlist;
UTF8String dynamicViaCORS;
IdentityCredentialUserData uiHint;
};
// Heavyweight only
// https://fedidcg.github.io/FedCM/#dictdef-identityproviderwellknown
[GenerateInit]
dictionary IdentityProviderWellKnown {
@ -85,9 +114,3 @@ dictionary IdentityProviderClientMetadata {
dictionary IdentityProviderToken {
required USVString token;
};
// https://fedidcg.github.io/FedCM/#dictdef-identitycredentiallogoutrpsrequest
dictionary IdentityCredentialLogoutRPsRequest {
required UTF8String url;
required UTF8String accountId;
};

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

@ -669,6 +669,11 @@ class PromptDelegateTest : BaseSessionTest(
"dom.security.credentialmanagement.identity.enabled" to true,
),
)
sessionRule.setPrefsUntilTestEnd(
mapOf(
"dom.security.credentialmanagement.identity.heavyweight.enabled" to true,
),
)
sessionRule.setPrefsUntilTestEnd(
mapOf(
"dom.security.credentialmanagement.identity.test_ignore_well_known" to true,

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

@ -3852,6 +3852,18 @@
value: false
mirror: always
# pref controls "heavyweight" network discoverable `identity` credentials being exposed
- name: dom.security.credentialmanagement.identity.heavyweight.enabled
type: bool
value: false
mirror: always
# pref controls storable "lightweight" `identity` credentials being exposed
- name: dom.security.credentialmanagement.identity.lightweight.enabled
type: bool
value: false
mirror: always
# pref controls `identity` credential UI for testing. When true, UI is not shown and
# the first option in the account and provider lists are chosen
- name: dom.security.credentialmanagement.identity.select_first_in_ui_lists

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

@ -2,6 +2,7 @@
head = "head.js"
prefs = [
"dom.security.credentialmanagement.identity.enabled=true",
"dom.security.credentialmanagement.identity.heavyweight.enabled=true",
"dom.security.credentialmanagement.identity.ignore_well_known=true",
"privacy.antitracking.enableWebcompat=false",
] # disables opener heuristic