blob: 6f017a89bcd7ffb2c17088724872710ef91c6e7f [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/identity/identity_api.h"
#include <stddef.h>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "base/lazy_instance.h"
#include "base/macros.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event.h"
#include "base/values.h"
#include "build/build_config.h"
#include "chrome/browser/app_mode/app_mode_utils.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/account_consistency_mode_manager.h"
#include "chrome/browser/signin/chrome_signin_client_factory.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/common/extensions/api/identity.h"
#include "chrome/common/url_constants.h"
#include "extensions/browser/extension_function_dispatcher.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_l10n_util.h"
#include "extensions/common/manifest_handlers/oauth2_manifest_handler.h"
#include "extensions/common/permissions/permission_set.h"
#include "extensions/common/permissions/permissions_data.h"
#include "google_apis/gaia/gaia_urls.h"
#include "url/gurl.h"
namespace extensions {
namespace {
const char kIdentityGaiaIdPref[] = "identity_gaia_id";
}
IdentityAPI::IdentityAPI(content::BrowserContext* context)
: IdentityAPI(Profile::FromBrowserContext(context),
IdentityManagerFactory::GetForProfile(
Profile::FromBrowserContext(context)),
ExtensionPrefs::Get(context),
EventRouter::Get(context)) {}
IdentityAPI::~IdentityAPI() {}
IdentityMintRequestQueue* IdentityAPI::mint_queue() { return &mint_queue_; }
IdentityTokenCache* IdentityAPI::token_cache() {
return &token_cache_;
}
void IdentityAPI::SetGaiaIdForExtension(const std::string& extension_id,
const std::string& gaia_id) {
DCHECK(!gaia_id.empty());
extension_prefs_->UpdateExtensionPref(extension_id, kIdentityGaiaIdPref,
std::make_unique<base::Value>(gaia_id));
}
base::Optional<std::string> IdentityAPI::GetGaiaIdForExtension(
const std::string& extension_id) {
std::string gaia_id;
if (!extension_prefs_->ReadPrefAsString(extension_id, kIdentityGaiaIdPref,
&gaia_id)) {
return base::nullopt;
}
return gaia_id;
}
void IdentityAPI::EraseGaiaIdForExtension(const std::string& extension_id) {
extension_prefs_->UpdateExtensionPref(extension_id, kIdentityGaiaIdPref,
nullptr);
}
void IdentityAPI::EraseStaleGaiaIdsForAllExtensions() {
// Refresh tokens haven't been loaded yet. Wait for OnRefreshTokensLoaded() to
// fire.
if (!identity_manager_->AreRefreshTokensLoaded())
return;
std::vector<CoreAccountInfo> accounts =
identity_manager_->GetAccountsWithRefreshTokens();
extensions::ExtensionIdList extensions;
extension_prefs_->GetExtensions(&extensions);
for (const ExtensionId& extension_id : extensions) {
base::Optional<std::string> gaia_id = GetGaiaIdForExtension(extension_id);
if (!gaia_id)
continue;
auto account_it = std::find_if(accounts.begin(), accounts.end(),
[&](const CoreAccountInfo& account) {
return account.gaia == *gaia_id;
});
if (account_it == accounts.end()) {
EraseGaiaIdForExtension(extension_id);
}
}
}
void IdentityAPI::SetConsentResult(const std::string& result,
const std::string& window_id) {
on_set_consent_result_callback_list_.Notify(result, window_id);
}
base::CallbackListSubscription IdentityAPI::RegisterOnSetConsentResultCallback(
const base::RepeatingCallback<OnSetConsentResultSignature>& callback) {
return on_set_consent_result_callback_list_.Add(callback);
}
void IdentityAPI::Shutdown() {
on_shutdown_callback_list_.Notify();
identity_manager_->RemoveObserver(this);
}
static base::LazyInstance<BrowserContextKeyedAPIFactory<IdentityAPI>>::
DestructorAtExit g_identity_api_factory = LAZY_INSTANCE_INITIALIZER;
// static
BrowserContextKeyedAPIFactory<IdentityAPI>* IdentityAPI::GetFactoryInstance() {
return g_identity_api_factory.Pointer();
}
base::CallbackListSubscription IdentityAPI::RegisterOnShutdownCallback(
base::OnceClosure cb) {
return on_shutdown_callback_list_.Add(std::move(cb));
}
bool IdentityAPI::AreExtensionsRestrictedToPrimaryAccount() {
return !AccountConsistencyModeManager::IsDiceEnabledForProfile(profile_) &&
!AccountConsistencyModeManager::IsMirrorEnabledForProfile(profile_);
}
IdentityAPI::IdentityAPI(Profile* profile,
signin::IdentityManager* identity_manager,
ExtensionPrefs* extension_prefs,
EventRouter* event_router)
: profile_(profile),
identity_manager_(identity_manager),
extension_prefs_(extension_prefs),
event_router_(event_router) {
identity_manager_->AddObserver(this);
EraseStaleGaiaIdsForAllExtensions();
}
void IdentityAPI::OnRefreshTokensLoaded() {
EraseStaleGaiaIdsForAllExtensions();
}
void IdentityAPI::OnRefreshTokenUpdatedForAccount(
const CoreAccountInfo& account_info) {
// Refresh tokens are sometimes made available in contexts where
// AccountTrackerService is not tracking the account in question. Bail out in
// these cases.
if (account_info.gaia.empty())
return;
FireOnAccountSignInChanged(account_info.gaia, true);
}
void IdentityAPI::OnExtendedAccountInfoRemoved(
const AccountInfo& account_info) {
DCHECK(!account_info.gaia.empty());
EraseStaleGaiaIdsForAllExtensions();
FireOnAccountSignInChanged(account_info.gaia, false);
}
void IdentityAPI::FireOnAccountSignInChanged(const std::string& gaia_id,
bool is_signed_in) {
DCHECK(!gaia_id.empty());
api::identity::AccountInfo api_account_info;
api_account_info.id = gaia_id;
std::unique_ptr<base::ListValue> args =
api::identity::OnSignInChanged::Create(api_account_info, is_signed_in);
std::unique_ptr<Event> event(new Event(
events::IDENTITY_ON_SIGN_IN_CHANGED,
api::identity::OnSignInChanged::kEventName, std::move(args), profile_));
if (on_signin_changed_callback_for_testing_)
on_signin_changed_callback_for_testing_.Run(event.get());
event_router_->BroadcastEvent(std::move(event));
}
template <>
void BrowserContextKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies() {
DependsOn(ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
DependsOn(ChromeSigninClientFactory::GetInstance());
DependsOn(IdentityManagerFactory::GetInstance());
}
} // namespace extensions