зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1782088, part 3 - Utilize account chooser in FedCM flow, r=timhuang,webidl,smaug
Depends on D158779 Differential Revision: https://phabricator.services.mozilla.com/D158780
This commit is contained in:
Родитель
9ebb4bcdc4
Коммит
1b93ce03df
|
@ -11,9 +11,11 @@
|
|||
#include "mozilla/dom/IdentityNetworkHelpers.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/WindowGlobalChild.h"
|
||||
#include "mozilla/Components.h"
|
||||
#include "mozilla/ExpandedPrincipal.h"
|
||||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsEffectiveTLDService.h"
|
||||
#include "nsIIdentityCredentialPromptService.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -136,31 +138,48 @@ IdentityCredential::DiscoverFromExternalSource(
|
|||
// static
|
||||
RefPtr<IdentityCredential::GetIPCIdentityCredentialPromise>
|
||||
IdentityCredential::DiscoverFromExternalSourceInMainProcess(
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aPrincipal, CanonicalBrowsingContext* aBrowsingContext,
|
||||
const IdentityCredentialRequestOptions& aOptions) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aBrowsingContext);
|
||||
|
||||
// Make sure we have exactly one provider.
|
||||
// Make sure we have providers.
|
||||
if (!aOptions.mProviders.WasPassed() ||
|
||||
aOptions.mProviders.Value().Length() != 1) {
|
||||
aOptions.mProviders.Value().Length() < 1) {
|
||||
return IdentityCredential::GetIPCIdentityCredentialPromise::CreateAndReject(
|
||||
NS_ERROR_DOM_NOT_ALLOWED_ERR, __func__);
|
||||
}
|
||||
|
||||
// Get that provider
|
||||
IdentityProvider provider(aOptions.mProviders.Value()[0]);
|
||||
nsCOMPtr<nsIPrincipal> principal(aPrincipal);
|
||||
RefPtr<CanonicalBrowsingContext> browsingContext(aBrowsingContext);
|
||||
|
||||
return IdentityCredential::CreateCredential(aPrincipal, provider);
|
||||
// Have the user choose a provider.
|
||||
return PromptUserToSelectProvider(aBrowsingContext,
|
||||
aOptions.mProviders.Value())
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[principal, browsingContext](const IdentityProvider& provider) {
|
||||
return IdentityCredential::CreateCredential(
|
||||
principal, browsingContext, provider);
|
||||
},
|
||||
[](nsresult error) {
|
||||
return IdentityCredential::GetIPCIdentityCredentialPromise::
|
||||
CreateAndReject(error, __func__);
|
||||
});
|
||||
}
|
||||
|
||||
// static
|
||||
RefPtr<IdentityCredential::GetIPCIdentityCredentialPromise>
|
||||
IdentityCredential::CreateCredential(nsIPrincipal* aPrincipal,
|
||||
BrowsingContext* aBrowsingContext,
|
||||
const IdentityProvider& aProvider) {
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
MOZ_ASSERT(aBrowsingContext);
|
||||
|
||||
nsCOMPtr<nsIPrincipal> argumentPrincipal = aPrincipal;
|
||||
RefPtr<BrowsingContext> browsingContext(aBrowsingContext);
|
||||
|
||||
return IdentityCredential::CheckRootManifest(aPrincipal, aProvider)
|
||||
->Then(
|
||||
|
@ -190,21 +209,34 @@ IdentityCredential::CreateCredential(nsIPrincipal* aPrincipal,
|
|||
})
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[argumentPrincipal, aProvider](
|
||||
[argumentPrincipal, browsingContext, aProvider](
|
||||
const Tuple<IdentityInternalManifest, IdentityAccountList>&
|
||||
promiseResult) {
|
||||
IdentityInternalManifest currentManifest;
|
||||
IdentityAccountList accountList;
|
||||
Tie(currentManifest, accountList) = promiseResult;
|
||||
// Bug 1782088: We currently just use the first account
|
||||
if (!accountList.mAccounts.WasPassed() ||
|
||||
accountList.mAccounts.Value().Length() == 0) {
|
||||
return IdentityCredential::GetTokenPromise::CreateAndReject(
|
||||
return IdentityCredential::GetAccountPromise::CreateAndReject(
|
||||
NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
return IdentityCredential::FetchToken(
|
||||
argumentPrincipal, aProvider, currentManifest,
|
||||
accountList.mAccounts.Value()[0]);
|
||||
return PromptUserToSelectAccount(browsingContext, accountList,
|
||||
currentManifest);
|
||||
},
|
||||
[](nsresult error) {
|
||||
return IdentityCredential::GetAccountPromise::CreateAndReject(
|
||||
error, __func__);
|
||||
})
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[argumentPrincipal,
|
||||
aProvider](const Tuple<IdentityInternalManifest, IdentityAccount>&
|
||||
promiseResult) {
|
||||
IdentityInternalManifest currentManifest;
|
||||
IdentityAccount account;
|
||||
Tie(currentManifest, account) = promiseResult;
|
||||
return IdentityCredential::FetchToken(argumentPrincipal, aProvider,
|
||||
currentManifest, account);
|
||||
},
|
||||
[](nsresult error) {
|
||||
return IdentityCredential::GetTokenPromise::CreateAndReject(
|
||||
|
@ -224,7 +256,8 @@ IdentityCredential::CreateCredential(nsIPrincipal* aPrincipal,
|
|||
return IdentityCredential::GetIPCIdentityCredentialPromise::
|
||||
CreateAndResolve(credential, __func__);
|
||||
},
|
||||
[](nsresult error) {
|
||||
[browsingContext](nsresult error) {
|
||||
CloseUserInterface(browsingContext);
|
||||
return IdentityCredential::GetIPCIdentityCredentialPromise::
|
||||
CreateAndReject(error, __func__);
|
||||
});
|
||||
|
@ -371,8 +404,8 @@ IdentityCredential::FetchAccountList(
|
|||
// Build the principal to use for this connection
|
||||
// This is an expanded principal! It has the cookies of the IDP because it
|
||||
// subsumes the constituent principals. It also has no serializable origin,
|
||||
// so it won't send an Origin header even though this is a CORS mode request.
|
||||
// It accomplishes this without being a SystemPrincipal too.
|
||||
// so it won't send an Origin header even though this is a CORS mode
|
||||
// request. It accomplishes this without being a SystemPrincipal too.
|
||||
nsCOMPtr<nsIURI> idpURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(idpURI), configLocation);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -517,4 +550,128 @@ RefPtr<IdentityCredential::GetTokenPromise> IdentityCredential::FetchToken(
|
|||
});
|
||||
}
|
||||
|
||||
// static
|
||||
RefPtr<IdentityCredential::GetIdentityProviderPromise>
|
||||
IdentityCredential::PromptUserToSelectProvider(
|
||||
BrowsingContext* aBrowsingContext,
|
||||
const Sequence<IdentityProvider>& aProviders) {
|
||||
MOZ_ASSERT(aBrowsingContext);
|
||||
RefPtr<IdentityCredential::GetIdentityProviderPromise::Private>
|
||||
resultPromise =
|
||||
new IdentityCredential::GetIdentityProviderPromise::Private(__func__);
|
||||
|
||||
if (NS_WARN_IF(!aBrowsingContext)) {
|
||||
resultPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
nsresult error;
|
||||
nsCOMPtr<nsIIdentityCredentialPromptService> icPromptService =
|
||||
mozilla::components::IdentityCredentialPromptService::Service(&error);
|
||||
if (NS_WARN_IF(!icPromptService)) {
|
||||
resultPromise->Reject(error, __func__);
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(icPromptService);
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(wrapped->GetJSObjectGlobal()))) {
|
||||
resultPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> providersJS(jsapi.cx());
|
||||
bool success = ToJSValue(jsapi.cx(), aProviders, &providersJS);
|
||||
if (NS_WARN_IF(!success)) {
|
||||
resultPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
RefPtr<Promise> showPromptPromise;
|
||||
icPromptService->ShowProviderPrompt(aBrowsingContext, providersJS,
|
||||
getter_AddRefs(showPromptPromise));
|
||||
|
||||
RefPtr<DomPromiseListener> listener = new DomPromiseListener(
|
||||
[resultPromise](JSContext* aCx, JS::Handle<JS::Value> aValue) {
|
||||
IdentityProvider result;
|
||||
bool success = result.Init(aCx, aValue);
|
||||
if (!success) {
|
||||
resultPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return;
|
||||
}
|
||||
resultPromise->Resolve(result, __func__);
|
||||
},
|
||||
[resultPromise](nsresult aRv) { resultPromise->Reject(aRv, __func__); });
|
||||
showPromptPromise->AppendNativeHandler(listener);
|
||||
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
// static
|
||||
RefPtr<IdentityCredential::GetAccountPromise>
|
||||
IdentityCredential::PromptUserToSelectAccount(
|
||||
BrowsingContext* aBrowsingContext, const IdentityAccountList& aAccounts,
|
||||
const IdentityInternalManifest& aManifest) {
|
||||
MOZ_ASSERT(aBrowsingContext);
|
||||
RefPtr<IdentityCredential::GetAccountPromise::Private> resultPromise =
|
||||
new IdentityCredential::GetAccountPromise::Private(__func__);
|
||||
|
||||
if (NS_WARN_IF(!aBrowsingContext)) {
|
||||
resultPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
nsresult error;
|
||||
nsCOMPtr<nsIIdentityCredentialPromptService> icPromptService =
|
||||
mozilla::components::IdentityCredentialPromptService::Service(&error);
|
||||
if (NS_WARN_IF(!icPromptService)) {
|
||||
resultPromise->Reject(error, __func__);
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIXPConnectWrappedJS> wrapped = do_QueryInterface(icPromptService);
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.Init(wrapped->GetJSObjectGlobal()))) {
|
||||
resultPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> accountsJS(jsapi.cx());
|
||||
bool success = ToJSValue(jsapi.cx(), aAccounts, &accountsJS);
|
||||
if (NS_WARN_IF(!success)) {
|
||||
resultPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
RefPtr<Promise> showPromptPromise;
|
||||
icPromptService->ShowAccountListPrompt(aBrowsingContext, accountsJS,
|
||||
getter_AddRefs(showPromptPromise));
|
||||
|
||||
RefPtr<DomPromiseListener> listener = new DomPromiseListener(
|
||||
[resultPromise, aManifest](JSContext* aCx, JS::Handle<JS::Value> aValue) {
|
||||
IdentityAccount result;
|
||||
bool success = result.Init(aCx, aValue);
|
||||
if (!success) {
|
||||
resultPromise->Reject(NS_ERROR_FAILURE, __func__);
|
||||
return;
|
||||
}
|
||||
resultPromise->Resolve(MakeTuple(aManifest, result), __func__);
|
||||
},
|
||||
[resultPromise](nsresult aRv) { resultPromise->Reject(aRv, __func__); });
|
||||
showPromptPromise->AppendNativeHandler(listener);
|
||||
|
||||
return resultPromise;
|
||||
}
|
||||
|
||||
// static
|
||||
void IdentityCredential::CloseUserInterface(BrowsingContext* aBrowsingContext) {
|
||||
nsresult error;
|
||||
nsCOMPtr<nsIIdentityCredentialPromptService> icPromptService =
|
||||
mozilla::components::IdentityCredentialPromptService::Service(&error);
|
||||
if (NS_WARN_IF(!icPromptService)) {
|
||||
return;
|
||||
}
|
||||
icPromptService->Close(aBrowsingContext);
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#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 "mozilla/MozPromise.h"
|
||||
|
@ -20,6 +21,8 @@ class IdentityCredential final : public Credential {
|
|||
GetIdentityCredentialPromise;
|
||||
typedef MozPromise<IPCIdentityCredential, nsresult, true>
|
||||
GetIPCIdentityCredentialPromise;
|
||||
typedef MozPromise<IdentityProvider, nsresult, true>
|
||||
GetIdentityProviderPromise;
|
||||
typedef MozPromise<bool, nsresult, true> ValidationPromise;
|
||||
typedef MozPromise<IdentityInternalManifest, nsresult, true>
|
||||
GetManifestPromise;
|
||||
|
@ -28,6 +31,9 @@ class IdentityCredential final : public Credential {
|
|||
GetAccountListPromise;
|
||||
typedef MozPromise<Tuple<IdentityToken, IdentityAccount>, nsresult, true>
|
||||
GetTokenPromise;
|
||||
typedef MozPromise<Tuple<IdentityInternalManifest, IdentityAccount>, nsresult,
|
||||
true>
|
||||
GetAccountPromise;
|
||||
|
||||
explicit IdentityCredential(nsPIDOMWindowInner* aParent);
|
||||
|
||||
|
@ -51,7 +57,7 @@ class IdentityCredential final : public Credential {
|
|||
|
||||
static RefPtr<GetIPCIdentityCredentialPromise>
|
||||
DiscoverFromExternalSourceInMainProcess(
|
||||
nsIPrincipal* aPrincipal,
|
||||
nsIPrincipal* aPrincipal, CanonicalBrowsingContext* aBrowsingContext,
|
||||
const IdentityCredentialRequestOptions& aOptions);
|
||||
|
||||
// Create an IPC credential that can be passed back to the content process.
|
||||
|
@ -69,7 +75,8 @@ class IdentityCredential final : public Credential {
|
|||
// Will send network requests to the IDP. The details of which are in the
|
||||
// other static methods here.
|
||||
static RefPtr<GetIPCIdentityCredentialPromise> CreateCredential(
|
||||
nsIPrincipal* aPrincipal, const IdentityProvider& aProvider);
|
||||
nsIPrincipal* aPrincipal, BrowsingContext* aBrowsingContext,
|
||||
const IdentityProvider& aProvider);
|
||||
|
||||
// Performs a Fetch for the root manifest of the provided identity provider
|
||||
// and validates it as correct. The returned promise resolves with a bool
|
||||
|
@ -147,6 +154,16 @@ class IdentityCredential final : public Credential {
|
|||
const IdentityInternalManifest& aManifest,
|
||||
const IdentityAccount& aAccount);
|
||||
|
||||
static RefPtr<GetIdentityProviderPromise> PromptUserToSelectProvider(
|
||||
BrowsingContext* aBrowsingContext,
|
||||
const Sequence<IdentityProvider>& aProviders);
|
||||
|
||||
static RefPtr<GetAccountPromise> PromptUserToSelectAccount(
|
||||
BrowsingContext* aBrowsingContext, const IdentityAccountList& aAccounts,
|
||||
const IdentityInternalManifest& aManifest);
|
||||
|
||||
static void CloseUserInterface(BrowsingContext* aBrowsingContext);
|
||||
|
||||
private:
|
||||
nsAutoString mToken;
|
||||
};
|
||||
|
|
|
@ -1353,7 +1353,7 @@ IPCResult WindowGlobalParent::RecvDiscoverIdentityCredentialFromExternalSource(
|
|||
const IdentityCredentialRequestOptions& aOptions,
|
||||
const DiscoverIdentityCredentialFromExternalSourceResolver& aResolver) {
|
||||
IdentityCredential::DiscoverFromExternalSourceInMainProcess(
|
||||
DocumentPrincipal(), aOptions)
|
||||
DocumentPrincipal(), this->BrowsingContext(), aOptions)
|
||||
->Then(
|
||||
GetCurrentSerialEventTarget(), __func__,
|
||||
[aResolver](const IPCIdentityCredential& aResult) {
|
||||
|
|
|
@ -18,6 +18,7 @@ dictionary IdentityCredentialRequestOptions {
|
|||
sequence<IdentityProvider> providers;
|
||||
};
|
||||
|
||||
[GenerateConversionToJS]
|
||||
dictionary IdentityProvider {
|
||||
required USVString configURL;
|
||||
required USVString clientId;
|
||||
|
@ -63,7 +64,7 @@ dictionary IdentityAccount {
|
|||
};
|
||||
|
||||
// https://fedidcg.github.io/FedCM/#idp-api-accounts-endpoint
|
||||
[GenerateInit]
|
||||
[GenerateInit, GenerateConversionToJS]
|
||||
dictionary IdentityAccountList {
|
||||
sequence<IdentityAccount> accounts;
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче