385 lines
18 KiB
C++
385 lines
18 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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_IdentityCredential_h
|
|
#define mozilla_dom_IdentityCredential_h
|
|
|
|
#include "mozilla/dom/CanonicalBrowsingContext.h"
|
|
#include "mozilla/dom/Credential.h"
|
|
#include "mozilla/dom/IPCIdentityCredential.h"
|
|
#include "nsICredentialChosenCallback.h"
|
|
#include "mozilla/IdentityCredentialStorageService.h"
|
|
#include "mozilla/MozPromise.h"
|
|
|
|
namespace mozilla::dom {
|
|
|
|
// This is the primary starting point for FedCM in the platform.
|
|
// This class is the implementation of the IdentityCredential object
|
|
// that is the value returned from the navigator.credentials.get call
|
|
// 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;
|
|
friend class WindowGlobalChild;
|
|
|
|
public:
|
|
// These are promise types, all used to support the async implementation of
|
|
// this API. All are of the form MozPromise<RefPtr<T>, nsresult>.
|
|
// Tuples are included to shuffle additional values along, so that the
|
|
// intermediate state is entirely in the promise chain and we don't have to
|
|
// capture an early step's result into a callback for a subsequent promise.
|
|
typedef MozPromise<RefPtr<IdentityCredential>, nsresult, true>
|
|
GetIdentityCredentialPromise;
|
|
typedef MozPromise<nsTArray<RefPtr<IdentityCredential>>, nsresult, true>
|
|
GetIdentityCredentialsPromise;
|
|
typedef MozPromise<IPCIdentityCredential, nsresult, true>
|
|
GetIPCIdentityCredentialPromise;
|
|
typedef MozPromise<CopyableTArray<IPCIdentityCredential>, nsresult, true>
|
|
GetIPCIdentityCredentialsPromise;
|
|
typedef MozPromise<IdentityProviderRequestOptions, nsresult, true>
|
|
GetIdentityProviderRequestOptionsPromise;
|
|
typedef MozPromise<bool, nsresult, true> ValidationPromise;
|
|
typedef MozPromise<Maybe<IdentityProviderWellKnown>, nsresult, true>
|
|
GetRootManifestPromise;
|
|
typedef MozPromise<IdentityProviderAPIConfig, nsresult, true>
|
|
GetManifestPromise;
|
|
typedef std::tuple<IdentityProviderRequestOptions, IdentityProviderAPIConfig>
|
|
IdentityProviderRequestOptionsWithManifest;
|
|
typedef MozPromise<IdentityProviderRequestOptionsWithManifest, nsresult, true>
|
|
GetIdentityProviderRequestOptionsWithManifestPromise;
|
|
typedef MozPromise<
|
|
std::tuple<IdentityProviderAPIConfig, IdentityProviderAccountList>,
|
|
nsresult, true>
|
|
GetAccountListPromise;
|
|
typedef MozPromise<std::tuple<IdentityProviderToken, IdentityProviderAccount>,
|
|
nsresult, true>
|
|
GetTokenPromise;
|
|
typedef MozPromise<
|
|
std::tuple<IdentityProviderAPIConfig, IdentityProviderAccount>, nsresult,
|
|
true>
|
|
GetAccountPromise;
|
|
typedef MozPromise<IdentityProviderClientMetadata, nsresult, true>
|
|
GetMetadataPromise;
|
|
|
|
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;
|
|
|
|
// This builds a value from an IPC-friendly version. This type is returned
|
|
// to the caller of navigator.credentials.get, however we get an IPC friendly
|
|
// version back from the main process to the content process.
|
|
// This is a deep copy of the token, ID, and type.
|
|
void CopyValuesFrom(const IPCIdentityCredential& aOther);
|
|
|
|
// This is the inverse of CopyValuesFrom. Included for completeness.
|
|
IPCIdentityCredential MakeIPCIdentityCredential() const;
|
|
|
|
static already_AddRefed<IdentityCredential> Constructor(
|
|
const GlobalObject& aGlobal, const IdentityCredentialInit& aInit,
|
|
ErrorResult& aRv);
|
|
|
|
static already_AddRefed<Promise> Disconnect(
|
|
const GlobalObject& aGlobal,
|
|
const IdentityCredentialDisconnectOptions& aOptions, ErrorResult& aRv);
|
|
|
|
static RefPtr<MozPromise<bool, nsresult, true>> DisconnectInMainProcess(
|
|
nsIPrincipal* aDocumentPrincipal,
|
|
const IdentityCredentialDisconnectOptions& aOptions);
|
|
|
|
// Getter and setter for the token member of this class
|
|
void GetToken(nsAString& aToken) const;
|
|
void SetToken(const nsAString& aToken);
|
|
|
|
// Get the Origin of this credential's identity provider
|
|
void GetOrigin(nsACString& aOrigin, ErrorResult& aError) const;
|
|
|
|
static nsresult ShowCredentialChooser(
|
|
const RefPtr<CanonicalBrowsingContext>& aContext,
|
|
const nsTArray<IPCIdentityCredential>& aCredentials,
|
|
const RefPtr<nsICredentialChosenCallback>& aCallback);
|
|
|
|
static void GetCredential(nsPIDOMWindowInner* aParent,
|
|
const CredentialRequestOptions& aOptions,
|
|
bool aSameOriginWithAncestors,
|
|
const RefPtr<Promise>& aPromise);
|
|
|
|
static RefPtr<GetIPCIdentityCredentialPromise> GetCredentialInMainProcess(
|
|
nsIPrincipal* aPrincipal, CanonicalBrowsingContext* aBrowsingContext,
|
|
IdentityCredentialRequestOptions&& aOptions,
|
|
const CredentialMediationRequirement& aMediationRequirement,
|
|
bool aHasUserActivation);
|
|
|
|
static nsresult CanSilentlyCollect(nsIPrincipal* aPrincipal,
|
|
nsIPrincipal* aIDPPrincipal,
|
|
bool* aResult);
|
|
|
|
static Maybe<IdentityProviderAccount> FindAccountToReauthenticate(
|
|
const IdentityProviderRequestOptions& aProvider,
|
|
nsIPrincipal* aRPPrincipal,
|
|
const IdentityProviderAccountList& aAccountList);
|
|
|
|
static Maybe<IdentityProviderRequestOptionsWithManifest> SkipAccountChooser(
|
|
const Sequence<IdentityProviderRequestOptions>& aProviders,
|
|
const Sequence<GetManifestPromise::ResolveOrRejectValue>& aManifests);
|
|
|
|
static RefPtr<GenericPromise> AllowedToCollectCredential(
|
|
nsIPrincipal* aPrincipal, CanonicalBrowsingContext* aBrowsingContext,
|
|
const IdentityCredentialRequestOptions& aOptions,
|
|
IPCIdentityCredential aCredential);
|
|
|
|
static RefPtr<GetIPCIdentityCredentialsPromise>
|
|
CollectFromCredentialStoreInMainProcess(
|
|
nsIPrincipal* aPrincipal, CanonicalBrowsingContext* aBrowsingContext,
|
|
const IdentityCredentialRequestOptions& aOptions);
|
|
|
|
static RefPtr<GenericPromise> Store(nsPIDOMWindowInner* aParent,
|
|
const IdentityCredential* aCredential,
|
|
bool aSameOriginWithAncestors);
|
|
|
|
static RefPtr<GenericPromise> StoreInMainProcess(
|
|
nsIPrincipal* aPrincipal, const IPCIdentityCredential& aCredential);
|
|
|
|
static RefPtr<GetIdentityCredentialPromise> Create(
|
|
nsPIDOMWindowInner* aParent, const CredentialCreationOptions& aOptions,
|
|
bool aSameOriginWithAncestors);
|
|
|
|
// Start the FedCM flow. This will start the timeout timer, fire initial
|
|
// network requests, prompt the user, and call into CreateCredential.
|
|
//
|
|
// Arguments:
|
|
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
|
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
|
// aOptions: argument passed to navigator.credentials.get()
|
|
// Return value:
|
|
// a promise resolving to an IPC credential with type "identity", id
|
|
// constructed to identify it, and token corresponding to the token
|
|
// fetched in FetchToken. This promise may reject with nsresult errors.
|
|
// Side effects:
|
|
// Will send network requests to the IDP. The details of which are in the
|
|
// other static methods here.
|
|
static RefPtr<GetIPCIdentityCredentialPromise>
|
|
DiscoverFromExternalSourceInMainProcess(
|
|
nsIPrincipal* aPrincipal, CanonicalBrowsingContext* aBrowsingContext,
|
|
const IdentityCredentialRequestOptions& aOptions,
|
|
const CredentialMediationRequirement& aMediationRequirement);
|
|
|
|
static RefPtr<GetIPCIdentityCredentialPromise>
|
|
DiscoverLightweightFromExternalSourceInMainProcess(
|
|
nsIPrincipal* aPrincipal, CanonicalBrowsingContext* aBrowsingContext,
|
|
const IdentityCredentialRequestOptions& aOptions);
|
|
|
|
// Create an IPC credential that can be passed back to the content process.
|
|
// This calls a lot of helpers to do the logic of going from a single provider
|
|
// to a bearer token for an account at that provider.
|
|
//
|
|
// Arguments:
|
|
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
|
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
|
// aProvider: the provider to validate the root manifest of
|
|
// aManifest: the internal manifest of the identity provider
|
|
// Return value:
|
|
// a promise resolving to an IPC credential with type "identity", id
|
|
// constructed to identify it, and token corresponding to the token
|
|
// fetched in FetchToken. This promise may reject with nsresult errors.
|
|
// Side effects:
|
|
// Will send network requests to the IDP. The details of which are in the
|
|
// other static methods here.
|
|
static RefPtr<GetIPCIdentityCredentialPromise>
|
|
CreateHeavyweightCredentialDuringDiscovery(
|
|
nsIPrincipal* aPrincipal, BrowsingContext* aBrowsingContext,
|
|
const IdentityProviderRequestOptions& aProvider,
|
|
const IdentityProviderAPIConfig& aManifest,
|
|
const CredentialMediationRequirement& aMediationRequirement);
|
|
|
|
// Performs a Fetch for the root manifest of the provided identity provider
|
|
// if needed and validates its structure. The returned promise resolves
|
|
// if a regular manifest fetch can proceed, with a root manifest value if
|
|
// one was fetched
|
|
//
|
|
// Arguments:
|
|
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
|
// aProvider: the provider to validate the root manifest of
|
|
// Return value:
|
|
// promise that resolves to a root manifest if one is fetched. Will reject
|
|
// when there are network or other errors.
|
|
// Side effects:
|
|
// Network request to the IDP's well-known if it is needed
|
|
//
|
|
static RefPtr<GetRootManifestPromise> FetchRootManifest(
|
|
nsIPrincipal* aPrincipal, const IdentityProviderConfig& aProvider);
|
|
|
|
// Performs a Fetch for the internal manifest of the provided identity
|
|
// provider. The returned promise resolves with the manifest retrieved.
|
|
//
|
|
// Arguments:
|
|
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
|
// aProvider: the provider to fetch the root manifest
|
|
// Return value:
|
|
// promise that resolves to the internal manifest. Will reject
|
|
// when there are network or other errors.
|
|
// Side effects:
|
|
// Network request to the URL in aProvider as the manifest from inside a
|
|
// NullPrincipal sandbox
|
|
//
|
|
static RefPtr<GetManifestPromise> FetchManifest(
|
|
nsIPrincipal* aPrincipal, const IdentityProviderConfig& aProvider);
|
|
|
|
// Performs a Fetch for the account list from the provided identity
|
|
// provider. The returned promise resolves with the manifest and the fetched
|
|
// account list in a tuple of objects. We put the argument manifest in the
|
|
// tuple to facilitate clean promise chaining.
|
|
//
|
|
// Arguments:
|
|
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
|
// aProvider: the provider to get account lists from
|
|
// aManifest: the provider's internal manifest
|
|
// Return value:
|
|
// promise that resolves to a Tuple of the passed manifest and the fetched
|
|
// account list. Will reject when there are network or other errors.
|
|
// Side effects:
|
|
// Network request to the provider supplied account endpoint with
|
|
// credentials but without any indication of aPrincipal.
|
|
//
|
|
static RefPtr<GetAccountListPromise> FetchAccountList(
|
|
nsIPrincipal* aPrincipal, const IdentityProviderRequestOptions& aProvider,
|
|
const IdentityProviderAPIConfig& aManifest);
|
|
|
|
// Performs a Fetch for a bearer token to the provided identity
|
|
// provider for a given account. The returned promise resolves with the
|
|
// account argument and the fetched token in a tuple of objects.
|
|
// We put the argument account in the
|
|
// tuple to facilitate clean promise chaining.
|
|
//
|
|
// Arguments:
|
|
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
|
// aProvider: the provider to get account lists from
|
|
// aManifest: the provider's internal manifest
|
|
// aAccount: the account to request
|
|
// Return value:
|
|
// promise that resolves to a Tuple of the passed account and the fetched
|
|
// token. Will reject when there are network or other errors.
|
|
// Side effects:
|
|
// Network request to the provider supplied token endpoint with
|
|
// credentials and including information about the requesting principal.
|
|
//
|
|
static RefPtr<GetTokenPromise> FetchToken(
|
|
nsIPrincipal* aPrincipal, const IdentityProviderRequestOptions& aProvider,
|
|
const IdentityProviderAPIConfig& aManifest,
|
|
const IdentityProviderAccount& aAccount);
|
|
|
|
// Performs a Fetch for links to legal info about the identity provider.
|
|
// The returned promise resolves with the information in an object.
|
|
//
|
|
// Arguments:
|
|
// aPrincipal: the caller of navigator.credentials.get()'s principal
|
|
// aProvider: the identity provider to get information from
|
|
// aManfiest: the identity provider's manifest
|
|
// Return value:
|
|
// promise that resolves with an object containing legal information for
|
|
// aProvider
|
|
// Side effects:
|
|
// Network request to the provider supplied token endpoint with
|
|
// credentials and including information about the requesting principal.
|
|
//
|
|
static RefPtr<GetMetadataPromise> FetchMetadata(
|
|
nsIPrincipal* aPrincipal, const IdentityProviderRequestOptions& aProvider,
|
|
const IdentityProviderAPIConfig& aManifest);
|
|
|
|
// Show the user a dialog to select what identity provider they would like
|
|
// to try to log in with.
|
|
//
|
|
// Arguments:
|
|
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
|
// aProviders: the providers to let the user select from
|
|
// aManifests: the manifests
|
|
// Return value:
|
|
// a promise resolving to an identity provider that the user took action
|
|
// to select. This promise may reject with nsresult errors.
|
|
// Side effects:
|
|
// Will show a dialog to the user.
|
|
static RefPtr<GetIdentityProviderRequestOptionsWithManifestPromise>
|
|
PromptUserToSelectProvider(
|
|
BrowsingContext* aBrowsingContext,
|
|
const Sequence<IdentityProviderRequestOptions>& aProviders,
|
|
const Sequence<GetManifestPromise::ResolveOrRejectValue>& aManifests);
|
|
|
|
// Show the user a dialog to select what account they would like
|
|
// to try to log in with.
|
|
//
|
|
// Arguments:
|
|
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
|
// aAccounts: the accounts to let the user select from
|
|
// aProvider: the provider that was chosen
|
|
// aManifest: the identity provider that was chosen's manifest
|
|
// Return value:
|
|
// a promise resolving to an account that the user took action
|
|
// to select (and aManifest). This promise may reject with nsresult errors.
|
|
// Side effects:
|
|
// Will show a dialog to the user.
|
|
static RefPtr<GetAccountPromise> PromptUserToSelectAccount(
|
|
BrowsingContext* aBrowsingContext,
|
|
const IdentityProviderAccountList& aAccounts,
|
|
const IdentityProviderRequestOptions& aProvider,
|
|
const IdentityProviderAPIConfig& aManifest);
|
|
|
|
// Show the user a dialog to select what account they would like
|
|
// to try to log in with.
|
|
//
|
|
// Arguments:
|
|
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
|
// aAccount: the accounts the user chose
|
|
// aManifest: the identity provider that was chosen's manifest
|
|
// aProvider: the identity provider that was chosen
|
|
// Return value:
|
|
// a promise resolving to an account that the user agreed to use (and
|
|
// aManifest). This promise may reject with nsresult errors. This includes
|
|
// if the user denied the terms and privacy policy
|
|
// Side effects:
|
|
// Will show a dialog to the user. Will send a network request to the
|
|
// identity provider. Modifies the IdentityCredentialStorageService state
|
|
// for this account.
|
|
static RefPtr<GetAccountPromise> PromptUserWithPolicy(
|
|
BrowsingContext* aBrowsingContext, nsIPrincipal* aPrincipal,
|
|
const IdentityProviderAccount& aAccount,
|
|
const IdentityProviderAPIConfig& aManifest,
|
|
const IdentityProviderRequestOptions& aProvider);
|
|
|
|
// Close all dialogs associated with IdentityCredential generation on the
|
|
// provided browsing context
|
|
//
|
|
// Arguments:
|
|
// aBrowsingContext: the BC of the caller of navigator.credentials.get()
|
|
// Side effects:
|
|
// Will close a dialog shown to the user.
|
|
static void CloseUserInterface(BrowsingContext* aBrowsingContext);
|
|
|
|
private:
|
|
nsAutoString mToken; // only used by heavyweight-created credentials
|
|
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, NONE };
|
|
static RequestType DetermineRequestDiscoveryType(
|
|
const IdentityCredentialRequestOptions& aOptions);
|
|
};
|
|
|
|
} // namespace mozilla::dom
|
|
|
|
#endif // mozilla_dom_IdentityCredential_h
|