summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/signin/chrome_signin_client.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/chrome/browser/signin/chrome_signin_client.cc')
-rw-r--r--chromium/chrome/browser/signin/chrome_signin_client.cc369
1 files changed, 369 insertions, 0 deletions
diff --git a/chromium/chrome/browser/signin/chrome_signin_client.cc b/chromium/chrome/browser/signin/chrome_signin_client.cc
new file mode 100644
index 00000000000..3a5ea106adb
--- /dev/null
+++ b/chromium/chrome/browser/signin/chrome_signin_client.cc
@@ -0,0 +1,369 @@
+// Copyright 2014 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/signin/chrome_signin_client.h"
+
+#include <stddef.h>
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
+#include "build/buildflag.h"
+#include "build/chromeos_buildflags.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/content_settings/cookie_settings_factory.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "chrome/browser/enterprise/util/managed_browser_utils.h"
+#include "chrome/browser/profiles/profile_attributes_entry.h"
+#include "chrome/browser/profiles/profile_attributes_storage.h"
+#include "chrome/browser/profiles/profile_manager.h"
+#include "chrome/browser/profiles/profile_metrics.h"
+#include "chrome/browser/signin/account_consistency_mode_manager.h"
+#include "chrome/browser/signin/chrome_device_id_helper.h"
+#include "chrome/browser/signin/force_signin_verifier.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
+#include "chrome/browser/signin/signin_features.h"
+#include "chrome/browser/signin/signin_util.h"
+#include "chrome/common/buildflags.h"
+#include "chrome/common/channel_info.h"
+#include "chrome/common/pref_names.h"
+#include "components/content_settings/core/browser/cookie_settings.h"
+#include "components/metrics/metrics_service.h"
+#include "components/policy/core/browser/browser_policy_connector.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/cookie_settings_util.h"
+#include "components/signin/public/base/signin_buildflags.h"
+#include "components/signin/public/base/signin_pref_names.h"
+#include "components/signin/public/identity_manager/access_token_info.h"
+#include "components/signin/public/identity_manager/identity_manager.h"
+#include "components/signin/public/identity_manager/scope_set.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/network_service_instance.h"
+#include "content/public/browser/storage_partition.h"
+#include "google_apis/gaia/gaia_constants.h"
+#include "google_apis/gaia/gaia_urls.h"
+#include "url/gurl.h"
+
+#if BUILDFLAG(ENABLE_SUPERVISED_USERS)
+#include "chrome/browser/supervised_user/supervised_user_constants.h"
+#endif
+
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ash/net/delay_network_call.h"
+#include "chromeos/network/network_handler.h"
+#endif
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+#include "chrome/browser/lacros/account_manager/account_manager_util.h"
+#include "chromeos/crosapi/mojom/account_manager.mojom.h"
+#include "chromeos/lacros/lacros_service.h"
+#include "components/account_manager_core/account.h"
+#include "components/account_manager_core/account_manager_util.h"
+#include "third_party/abseil-cpp/absl/types/optional.h"
+#endif
+
+#if !defined(OS_ANDROID)
+#include "chrome/browser/profiles/profile_window.h"
+#endif
+
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+#include "chrome/browser/ui/browser_list.h"
+#include "chrome/browser/ui/profile_picker.h"
+#endif
+
+namespace {
+
+// List of sources for which sign out is always allowed.
+signin_metrics::ProfileSignout kAlwaysAllowedSignoutSources[] = {
+ // Allowed, because data has not been synced yet.
+ signin_metrics::ProfileSignout::ABORT_SIGNIN,
+ // Allowed, because only used on Android and the primary account must be
+ // cleared when the account is removed from device
+ signin_metrics::ProfileSignout::ACCOUNT_REMOVED_FROM_DEVICE,
+ // Allowed to force finish the account id migration.
+ signin_metrics::ACCOUNT_ID_MIGRATION,
+ // Allowed, for tests.
+ signin_metrics::ProfileSignout::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST};
+
+SigninClient::SignoutDecision IsSignoutAllowed(
+ Profile* profile,
+ const signin_metrics::ProfileSignout signout_source) {
+ if (signin_util::IsUserSignoutAllowedForProfile(profile))
+ return SigninClient::SignoutDecision::ALLOW_SIGNOUT;
+
+ auto* identity_manager =
+ IdentityManagerFactory::GetForProfileIfExists(profile);
+ if (identity_manager &&
+ !identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSync)) {
+ return SigninClient::SignoutDecision::ALLOW_SIGNOUT;
+ }
+
+ for (const auto& always_allowed_source : kAlwaysAllowedSignoutSources) {
+ if (signout_source == always_allowed_source)
+ return SigninClient::SignoutDecision::ALLOW_SIGNOUT;
+ }
+
+ return SigninClient::SignoutDecision::DISALLOW_SIGNOUT;
+}
+
+} // namespace
+
+ChromeSigninClient::ChromeSigninClient(Profile* profile) : profile_(profile) {
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+ content::GetNetworkConnectionTracker()->AddNetworkConnectionObserver(this);
+#endif
+}
+
+ChromeSigninClient::~ChromeSigninClient() {
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+ content::GetNetworkConnectionTracker()->RemoveNetworkConnectionObserver(this);
+#endif
+}
+
+void ChromeSigninClient::DoFinalInit() {
+ VerifySyncToken();
+}
+
+// static
+bool ChromeSigninClient::ProfileAllowsSigninCookies(Profile* profile) {
+ content_settings::CookieSettings* cookie_settings =
+ CookieSettingsFactory::GetForProfile(profile).get();
+ return signin::SettingsAllowSigninCookies(cookie_settings);
+}
+
+PrefService* ChromeSigninClient::GetPrefs() { return profile_->GetPrefs(); }
+
+scoped_refptr<network::SharedURLLoaderFactory>
+ChromeSigninClient::GetURLLoaderFactory() {
+ if (url_loader_factory_for_testing_)
+ return url_loader_factory_for_testing_;
+
+ return profile_->GetDefaultStoragePartition()
+ ->GetURLLoaderFactoryForBrowserProcess();
+}
+
+network::mojom::CookieManager* ChromeSigninClient::GetCookieManager() {
+ return profile_->GetDefaultStoragePartition()
+ ->GetCookieManagerForBrowserProcess();
+}
+
+bool ChromeSigninClient::AreSigninCookiesAllowed() {
+ return ProfileAllowsSigninCookies(profile_);
+}
+
+bool ChromeSigninClient::AreSigninCookiesDeletedOnExit() {
+ content_settings::CookieSettings* cookie_settings =
+ CookieSettingsFactory::GetForProfile(profile_).get();
+ return signin::SettingsDeleteSigninCookiesOnExit(cookie_settings);
+}
+
+void ChromeSigninClient::AddContentSettingsObserver(
+ content_settings::Observer* observer) {
+ HostContentSettingsMapFactory::GetForProfile(profile_)
+ ->AddObserver(observer);
+}
+
+void ChromeSigninClient::RemoveContentSettingsObserver(
+ content_settings::Observer* observer) {
+ HostContentSettingsMapFactory::GetForProfile(profile_)
+ ->RemoveObserver(observer);
+}
+
+void ChromeSigninClient::PreSignOut(
+ base::OnceCallback<void(SignoutDecision)> on_signout_decision_reached,
+ signin_metrics::ProfileSignout signout_source_metric) {
+ DCHECK(on_signout_decision_reached);
+ DCHECK(!on_signout_decision_reached_) << "SignOut already in-progress!";
+ on_signout_decision_reached_ = std::move(on_signout_decision_reached);
+
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+ // `signout_source_metric` is `signin_metrics::ABORT_SIGNIN` if the user
+ // declines sync in the signin process. In case the user accepts the managed
+ // account but declines sync, we should keep the window open.
+ bool user_declines_sync_after_consenting_to_management =
+ signout_source_metric == signin_metrics::ABORT_SIGNIN &&
+ chrome::enterprise_util::UserAcceptedAccountManagement(profile_);
+ // These sign out won't remove the policy cache, keep the window opened.
+ bool keep_window_opened =
+ signout_source_metric ==
+ signin_metrics::GOOGLE_SERVICE_NAME_PATTERN_CHANGED ||
+ signout_source_metric == signin_metrics::SERVER_FORCED_DISABLE ||
+ signout_source_metric == signin_metrics::SIGNOUT_PREF_CHANGED ||
+ user_declines_sync_after_consenting_to_management;
+ if (signin_util::IsForceSigninEnabled() && !profile_->IsSystemProfile() &&
+ !profile_->IsGuestSession() && !profile_->IsChild() &&
+ !keep_window_opened) {
+ if (signout_source_metric ==
+ signin_metrics::SIGNIN_PREF_CHANGED_DURING_SIGNIN) {
+ // SIGNIN_PREF_CHANGED_DURING_SIGNIN will be triggered when
+ // IdentityManager is initialized before window opening, there is no need
+ // to close window. Call OnCloseBrowsersSuccess to continue sign out and
+ // show UserManager afterwards.
+ should_display_user_manager_ = false; // Don't show UserManager twice.
+ OnCloseBrowsersSuccess(signout_source_metric, profile_->GetPath());
+ } else {
+ BrowserList::CloseAllBrowsersWithProfile(
+ profile_,
+ base::BindRepeating(&ChromeSigninClient::OnCloseBrowsersSuccess,
+ base::Unretained(this), signout_source_metric),
+ base::BindRepeating(&ChromeSigninClient::OnCloseBrowsersAborted,
+ base::Unretained(this)),
+ signout_source_metric == signin_metrics::ABORT_SIGNIN ||
+ signout_source_metric ==
+ signin_metrics::AUTHENTICATION_FAILED_WITH_FORCE_SIGNIN ||
+ signout_source_metric == signin_metrics::TRANSFER_CREDENTIALS);
+ }
+ } else {
+#else
+ {
+#endif
+ std::move(on_signout_decision_reached_)
+ .Run(IsSignoutAllowed(profile_, signout_source_metric));
+ }
+}
+
+#if !BUILDFLAG(IS_CHROMEOS_ASH)
+void ChromeSigninClient::OnConnectionChanged(
+ network::mojom::ConnectionType type) {
+ if (type == network::mojom::ConnectionType::CONNECTION_NONE)
+ return;
+
+ for (base::OnceClosure& callback : delayed_callbacks_)
+ std::move(callback).Run();
+
+ delayed_callbacks_.clear();
+}
+#endif
+
+void ChromeSigninClient::DelayNetworkCall(base::OnceClosure callback) {
+#if BUILDFLAG(IS_CHROMEOS_ASH)
+ // Do not make network requests in unit tests. chromeos::NetworkHandler should
+ // not be used and is not expected to have been initialized in unit tests.
+ if (url_loader_factory_for_testing_ &&
+ !chromeos::NetworkHandler::IsInitialized()) {
+ std::move(callback).Run();
+ return;
+ }
+ chromeos::DelayNetworkCall(
+ base::Milliseconds(chromeos::kDefaultNetworkRetryDelayMS),
+ std::move(callback));
+ return;
+#else
+ // Don't bother if we don't have any kind of network connection.
+ network::mojom::ConnectionType type;
+ bool sync = content::GetNetworkConnectionTracker()->GetConnectionType(
+ &type, base::BindOnce(&ChromeSigninClient::OnConnectionChanged,
+ weak_ptr_factory_.GetWeakPtr()));
+ if (!sync || type == network::mojom::ConnectionType::CONNECTION_NONE) {
+ // Connection type cannot be retrieved synchronously so delay the callback.
+ delayed_callbacks_.push_back(std::move(callback));
+ } else {
+ std::move(callback).Run();
+ }
+#endif
+}
+
+std::unique_ptr<GaiaAuthFetcher> ChromeSigninClient::CreateGaiaAuthFetcher(
+ GaiaAuthConsumer* consumer,
+ gaia::GaiaSource source) {
+ return std::make_unique<GaiaAuthFetcher>(consumer, source,
+ GetURLLoaderFactory());
+}
+
+void ChromeSigninClient::VerifySyncToken() {
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+ // We only verifiy the token once when Profile is just created.
+ if (signin_util::IsForceSigninEnabled() && !force_signin_verifier_)
+ force_signin_verifier_ = std::make_unique<ForceSigninVerifier>(
+ profile_, IdentityManagerFactory::GetForProfile(profile_));
+#endif
+}
+
+bool ChromeSigninClient::IsNonEnterpriseUser(const std::string& username) {
+ return policy::BrowserPolicyConnector::IsNonEnterpriseUser(username);
+}
+
+#if BUILDFLAG(IS_CHROMEOS_LACROS)
+// Returns the account that must be auto-signed-in to the Main Profile in
+// Lacros.
+// This is, when available, the account used to sign into the Chrome OS
+// session. This may be a Gaia account or a Microsoft Active Directory
+// account. This field will be null for Guest sessions, Managed Guest
+// sessions, Demo mode, and Kiosks. Note that this is different from the
+// concept of a Primary Account in the browser. A user may not be signed into
+// a Lacros browser Profile, or may be signed into a browser Profile with an
+// account which is different from the account which they used to sign into
+// the device - aka Device Account.
+// Also note that this will be null for Secondary / non-Main Profiles in
+// Lacros, because they do not start with the Chrome OS Device Account
+// signed-in by default.
+absl::optional<account_manager::Account>
+ChromeSigninClient::GetInitialPrimaryAccount() {
+ if (!profile_->IsMainProfile())
+ return absl::nullopt;
+
+ const crosapi::mojom::AccountPtr& device_account =
+ chromeos::LacrosService::Get()->init_params()->device_account;
+ if (!device_account)
+ return absl::nullopt;
+
+ return account_manager::FromMojoAccount(device_account);
+}
+#endif
+
+void ChromeSigninClient::SetURLLoaderFactoryForTest(
+ scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory) {
+ url_loader_factory_for_testing_ = url_loader_factory;
+}
+
+void ChromeSigninClient::OnCloseBrowsersSuccess(
+ const signin_metrics::ProfileSignout signout_source_metric,
+ const base::FilePath& profile_path) {
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+ if (signin_util::IsForceSigninEnabled() && force_signin_verifier_.get()) {
+ force_signin_verifier_->Cancel();
+ }
+#endif
+
+ std::move(on_signout_decision_reached_)
+ .Run(IsSignoutAllowed(profile_, signout_source_metric));
+
+ LockForceSigninProfile(profile_path);
+ // After sign out, lock the profile and show UserManager if necessary.
+ if (should_display_user_manager_) {
+ ShowUserManager(profile_path);
+ } else {
+ should_display_user_manager_ = true;
+ }
+}
+
+void ChromeSigninClient::OnCloseBrowsersAborted(
+ const base::FilePath& profile_path) {
+ should_display_user_manager_ = true;
+
+ // Disallow sign-out (aborted).
+ std::move(on_signout_decision_reached_)
+ .Run(SignoutDecision::DISALLOW_SIGNOUT);
+}
+
+void ChromeSigninClient::LockForceSigninProfile(
+ const base::FilePath& profile_path) {
+ ProfileAttributesEntry* entry =
+ g_browser_process->profile_manager()
+ ->GetProfileAttributesStorage()
+ .GetProfileAttributesWithPath(profile_->GetPath());
+ if (!entry)
+ return;
+ entry->LockForceSigninProfile(true);
+}
+
+void ChromeSigninClient::ShowUserManager(const base::FilePath& profile_path) {
+#if !defined(OS_ANDROID) && !BUILDFLAG(IS_CHROMEOS_ASH)
+ ProfilePicker::Show(ProfilePicker::EntryPoint::kProfileLocked);
+#endif
+}