| // Copyright 2013 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/ui/webui/chromeos/login/gaia_screen_handler.h" |
| |
| #include <memory> |
| |
| #include "ash/public/cpp/ash_features.h" |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/containers/flat_set.h" |
| #include "base/feature_list.h" |
| #include "base/guid.h" |
| #include "base/json/json_reader.h" |
| #include "base/logging.h" |
| #include "base/metrics/histogram_macros.h" |
| #include "base/stl_util.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/sys_info.h" |
| #include "base/task/post_task.h" |
| #include "base/values.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/chromeos/language_preferences.h" |
| #include "chrome/browser/chromeos/login/lock_screen_utils.h" |
| #include "chrome/browser/chromeos/login/reauth_stats.h" |
| #include "chrome/browser/chromeos/login/screens/network_error.h" |
| #include "chrome/browser/chromeos/login/signin_partition_manager.h" |
| #include "chrome/browser/chromeos/login/ui/login_display_host.h" |
| #include "chrome/browser/chromeos/login/ui/login_display_host_webui.h" |
| #include "chrome/browser/chromeos/login/ui/user_adding_screen.h" |
| #include "chrome/browser/chromeos/login/users/chrome_user_manager.h" |
| #include "chrome/browser/chromeos/login/users/chrome_user_manager_util.h" |
| #include "chrome/browser/chromeos/net/network_portal_detector_impl.h" |
| #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" |
| #include "chrome/browser/chromeos/policy/device_network_configuration_updater.h" |
| #include "chrome/browser/chromeos/policy/temp_certs_cache_nss.h" |
| #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| #include "chrome/browser/chromeos/settings/cros_settings.h" |
| #include "chrome/browser/lifetime/browser_shutdown.h" |
| #include "chrome/browser/net/system_network_context_manager.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/ui/ash/login_screen_client.h" |
| #include "chrome/browser/ui/webui/chromeos/login/active_directory_password_change_screen_handler.h" |
| #include "chrome/browser/ui/webui/chromeos/login/enrollment_screen_handler.h" |
| #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h" |
| #include "chrome/browser/ui/webui/metrics_handler.h" |
| #include "chrome/browser/ui/webui/signin/signin_utils.h" |
| #include "chrome/common/channel_info.h" |
| #include "chrome/common/chrome_features.h" |
| #include "chrome/common/pref_names.h" |
| #include "chrome/grit/generated_resources.h" |
| #include "chrome/installer/util/google_update_settings.h" |
| #include "chromeos/chromeos_switches.h" |
| #include "chromeos/dbus/util/version_loader.h" |
| #include "chromeos/login/auth/authpolicy_login_helper.h" |
| #include "chromeos/login/auth/user_context.h" |
| #include "chromeos/settings/cros_settings_names.h" |
| #include "chromeos/system/devicetype.h" |
| #include "components/login/localized_values_builder.h" |
| #include "components/policy/proto/chrome_device_policy.pb.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/strings/grit/components_strings.h" |
| #include "components/user_manager/known_user.h" |
| #include "components/user_manager/user_manager.h" |
| #include "components/version_info/version_info.h" |
| #include "content/public/browser/browser_thread.h" |
| #include "content/public/browser/render_frame_host.h" |
| #include "google_apis/gaia/gaia_auth_util.h" |
| #include "google_apis/gaia/gaia_urls.h" |
| #include "mojo/public/cpp/bindings/callback_helpers.h" |
| #include "services/network/public/mojom/network_context.mojom.h" |
| #include "ui/base/ime/chromeos/input_method_manager.h" |
| #include "ui/base/ime/chromeos/input_method_util.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/chromeos/devicetype_utils.h" |
| |
| using content::BrowserThread; |
| namespace em = enterprise_management; |
| |
| namespace chromeos { |
| |
| namespace { |
| |
| const char kJsScreenPath[] = "login.GaiaSigninScreen"; |
| const char kAuthIframeParentName[] = "signin-frame"; |
| |
| const char kRestrictiveProxyURL[] = "https://www.google.com/generate_204"; |
| |
| const char kEndpointGen[] = "1.0"; |
| |
| // The possible modes that the Gaia signin screen can be in. |
| enum GaiaScreenMode { |
| // Default Gaia authentication will be used. |
| GAIA_SCREEN_MODE_DEFAULT = 0, |
| |
| // Gaia offline mode will be used. |
| GAIA_SCREEN_MODE_OFFLINE = 1, |
| |
| // An interstitial page will be used before SAML redirection. |
| GAIA_SCREEN_MODE_SAML_INTERSTITIAL = 2, |
| |
| // Offline UI for Active Directory authentication. |
| GAIA_SCREEN_MODE_AD = 3, |
| }; |
| |
| policy::DeviceMode GetDeviceMode() { |
| policy::BrowserPolicyConnectorChromeOS* connector = |
| g_browser_process->platform_part()->browser_policy_connector_chromeos(); |
| return connector->GetDeviceMode(); |
| } |
| |
| GaiaScreenMode GetGaiaScreenMode(const std::string& email, bool use_offline) { |
| if (use_offline) |
| return GAIA_SCREEN_MODE_OFFLINE; |
| |
| if (GetDeviceMode() == policy::DEVICE_MODE_ENTERPRISE_AD) |
| return GAIA_SCREEN_MODE_AD; |
| |
| int authentication_behavior = 0; |
| CrosSettings::Get()->GetInteger(kLoginAuthenticationBehavior, |
| &authentication_behavior); |
| if (authentication_behavior == |
| em::LoginAuthenticationBehaviorProto::SAML_INTERSTITIAL) { |
| if (email.empty()) |
| return GAIA_SCREEN_MODE_SAML_INTERSTITIAL; |
| |
| // If there's a populated email, we must check first that this user is using |
| // SAML in order to decide whether to show the interstitial page. |
| const user_manager::User* user = user_manager::UserManager::Get()->FindUser( |
| user_manager::known_user::GetAccountId(email, std::string() /* id */, |
| AccountType::UNKNOWN)); |
| |
| if (user && user->using_saml()) |
| return GAIA_SCREEN_MODE_SAML_INTERSTITIAL; |
| } |
| |
| return GAIA_SCREEN_MODE_DEFAULT; |
| } |
| |
| std::string GetEnterpriseDisplayDomain() { |
| policy::BrowserPolicyConnectorChromeOS* connector = |
| g_browser_process->platform_part()->browser_policy_connector_chromeos(); |
| return connector->GetEnterpriseDisplayDomain(); |
| } |
| |
| std::string GetEnterpriseEnrollmentDomain() { |
| policy::BrowserPolicyConnectorChromeOS* connector = |
| g_browser_process->platform_part()->browser_policy_connector_chromeos(); |
| return connector->GetEnterpriseEnrollmentDomain(); |
| } |
| |
| std::string GetRealm() { |
| policy::BrowserPolicyConnectorChromeOS* connector = |
| g_browser_process->platform_part()->browser_policy_connector_chromeos(); |
| return connector->GetRealm(); |
| } |
| |
| std::string GetChromeType() { |
| switch (chromeos::GetDeviceType()) { |
| case chromeos::DeviceType::kChromebox: |
| return "chromebox"; |
| case chromeos::DeviceType::kChromebase: |
| return "chromebase"; |
| case chromeos::DeviceType::kChromebit: |
| return "chromebit"; |
| case chromeos::DeviceType::kChromebook: |
| return "chromebook"; |
| default: |
| return "chromedevice"; |
| } |
| } |
| |
| void UpdateAuthParams(base::DictionaryValue* params, |
| bool is_restrictive_proxy) { |
| CrosSettings* cros_settings = CrosSettings::Get(); |
| bool allow_new_user = true; |
| cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user); |
| params->SetBoolean("guestSignin", |
| user_manager::UserManager::Get()->IsGuestSessionAllowed()); |
| |
| // nosignup flow if new users are not allowed. |
| if (!allow_new_user || is_restrictive_proxy) |
| params->SetString("flow", "nosignup"); |
| |
| params->SetBoolean("supervisedUsersCanCreate", false); |
| |
| // Now check whether we're in multi-profiles user adding scenario and |
| // disable GAIA right panel features if that's the case. |
| if (UserAddingScreen::Get()->IsRunning()) { |
| params->SetBoolean("guestSignin", false); |
| params->SetBoolean("supervisedUsersCanCreate", false); |
| } |
| } |
| |
| void RecordSAMLScrapingVerificationResultInHistogram(bool success) { |
| UMA_HISTOGRAM_BOOLEAN("ChromeOS.SAML.Scraping.VerificationResult", success); |
| } |
| |
| void PushFrontIMIfNotExists(const std::string& input_method, |
| std::vector<std::string>* input_methods) { |
| if (input_method.empty()) |
| return; |
| |
| if (!base::ContainsValue(*input_methods, input_method)) |
| input_methods->insert(input_methods->begin(), input_method); |
| } |
| |
| bool IsOnline(NetworkPortalDetector::CaptivePortalStatus status) { |
| return status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE; |
| } |
| |
| void GetVersionAndConsent(std::string* out_version, bool* out_consent) { |
| *out_version = version_loader::GetVersion(version_loader::VERSION_SHORT); |
| *out_consent = GoogleUpdateSettings::GetCollectStatsConsent(); |
| } |
| |
| user_manager::UserType GetUsertypeFromServicesString( |
| const ::login::StringList& services) { |
| bool is_child = false; |
| const bool support_usm = |
| base::FeatureList::IsEnabled(features::kCrOSEnableUSMUserService); |
| using KnownFlags = base::flat_set<std::string>; |
| const KnownFlags known_flags = |
| support_usm ? KnownFlags({"uca", "usm"}) : KnownFlags({"uca"}); |
| |
| size_t i = 0; |
| for (const std::string& item : services) { |
| if (known_flags.find(item) != known_flags.end()) { |
| is_child = true; |
| } |
| ++i; |
| } |
| |
| return is_child ? user_manager::USER_TYPE_CHILD |
| : user_manager::USER_TYPE_REGULAR; |
| } |
| |
| user_manager::UserType CalculateUserType(const AccountId& account_id) { |
| if (user_manager::UserManager::Get()->IsSupervisedAccountId(account_id)) |
| return user_manager::USER_TYPE_SUPERVISED; |
| |
| if (account_id.GetAccountType() == AccountType::ACTIVE_DIRECTORY) |
| return user_manager::USER_TYPE_ACTIVE_DIRECTORY; |
| |
| return user_manager::USER_TYPE_REGULAR; |
| } |
| |
| std::string GetAdErrorMessage(authpolicy::ErrorType error) { |
| switch (error) { |
| case authpolicy::ERROR_NETWORK_PROBLEM: |
| return l10n_util::GetStringUTF8(IDS_AD_AUTH_NETWORK_ERROR); |
| case authpolicy::ERROR_KDC_DOES_NOT_SUPPORT_ENCRYPTION_TYPE: |
| return l10n_util::GetStringUTF8(IDS_AD_AUTH_NOT_SUPPORTED_ENCRYPTION); |
| default: |
| DLOG(WARNING) << "Unhandled error code: " << error; |
| return l10n_util::GetStringUTF8(IDS_AD_AUTH_UNKNOWN_ERROR); |
| } |
| } |
| |
| } // namespace |
| |
| // A class that's used to specify the way how Gaia should be loaded. |
| struct GaiaScreenHandler::GaiaContext { |
| GaiaContext(); |
| |
| // Forces Gaia to reload. |
| bool force_reload = false; |
| |
| // Whether Gaia should be loaded in offline mode. |
| bool use_offline = false; |
| |
| // Email of the current user. |
| std::string email; |
| |
| // GAIA ID of the current user. |
| std::string gaia_id; |
| |
| // GAPS cookie. |
| std::string gaps_cookie; |
| }; |
| |
| GaiaScreenHandler::GaiaContext::GaiaContext() {} |
| |
| GaiaScreenHandler::GaiaScreenHandler( |
| CoreOobeView* core_oobe_view, |
| const scoped_refptr<NetworkStateInformer>& network_state_informer, |
| ActiveDirectoryPasswordChangeScreenHandler* |
| active_directory_password_change_screen_handler) |
| : BaseScreenHandler(kScreenId), |
| network_state_informer_(network_state_informer), |
| core_oobe_view_(core_oobe_view), |
| active_directory_password_change_screen_handler_( |
| active_directory_password_change_screen_handler), |
| weak_factory_(this) { |
| DCHECK(network_state_informer_.get()); |
| set_call_js_prefix(kJsScreenPath); |
| } |
| |
| GaiaScreenHandler::~GaiaScreenHandler() { |
| if (network_portal_detector_) |
| network_portal_detector_->RemoveObserver(this); |
| } |
| |
| void GaiaScreenHandler::MaybePreloadAuthExtension() { |
| // We shall not have network portal detector initialized, which unnecessarily |
| // polls captive portal checking URL if we don't need to load gaia. See |
| // go/bad-portal for more context. |
| if (!signin_screen_handler_->ShouldLoadGaia()) |
| return; |
| |
| VLOG(1) << "MaybePreloadAuthExtension"; |
| |
| if (!network_portal_detector_) { |
| NetworkPortalDetectorImpl* detector = new NetworkPortalDetectorImpl( |
| g_browser_process->system_network_context_manager() |
| ->GetURLLoaderFactory()); |
| detector->set_portal_test_url(GURL(kRestrictiveProxyURL)); |
| network_portal_detector_.reset(detector); |
| network_portal_detector_->AddObserver(this); |
| network_portal_detector_->Enable(true); |
| } |
| |
| // If cookies clearing was initiated or |dns_clear_task_running_| then auth |
| // extension showing has already been initiated and preloading is pointless. |
| if (!gaia_silent_load_ && !cookies_cleared_ && !dns_clear_task_running_ && |
| network_state_informer_->state() == NetworkStateInformer::ONLINE) { |
| gaia_silent_load_ = true; |
| gaia_silent_load_network_ = network_state_informer_->network_path(); |
| LoadAuthExtension(true /* force */, false /* offline */); |
| } |
| } |
| |
| void GaiaScreenHandler::DisableRestrictiveProxyCheckForTest() { |
| disable_restrictive_proxy_check_for_test_ = true; |
| } |
| |
| void GaiaScreenHandler::LoadGaia(const GaiaContext& context) { |
| // Start a new session with SigninPartitionManager, generating a unique |
| // StoragePartition. |
| login::SigninPartitionManager* signin_partition_manager = |
| login::SigninPartitionManager::Factory::GetForBrowserContext( |
| Profile::FromWebUI(web_ui())); |
| signin_partition_manager->StartSigninSession( |
| web_ui()->GetWebContents(), |
| base::BindOnce(&GaiaScreenHandler::LoadGaiaWithPartition, |
| weak_factory_.GetWeakPtr(), context)); |
| } |
| |
| void GaiaScreenHandler::LoadGaiaWithPartition( |
| const GaiaContext& context, |
| const std::string& partition_name) { |
| std::unique_ptr<std::string> version = std::make_unique<std::string>(); |
| std::unique_ptr<bool> consent = std::make_unique<bool>(); |
| base::OnceClosure get_version_and_consent = |
| base::BindOnce(&GetVersionAndConsent, base::Unretained(version.get()), |
| base::Unretained(consent.get())); |
| base::OnceClosure load_gaia = base::BindOnce( |
| &GaiaScreenHandler::LoadGaiaWithPartitionAndVersionAndConsent, |
| weak_factory_.GetWeakPtr(), context, partition_name, |
| base::Owned(version.release()), base::Owned(consent.release())); |
| base::PostTaskWithTraitsAndReply( |
| FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, |
| std::move(get_version_and_consent), std::move(load_gaia)); |
| } |
| |
| void GaiaScreenHandler::LoadGaiaWithPartitionAndVersionAndConsent( |
| const GaiaContext& context, |
| const std::string& partition_name, |
| const std::string* platform_version, |
| const bool* collect_stats_consent) { |
| base::DictionaryValue params; |
| |
| params.SetBoolean("forceReload", context.force_reload); |
| params.SetString("gaiaId", context.gaia_id); |
| params.SetBoolean("readOnlyEmail", true); |
| params.SetString("email", context.email); |
| params.SetString("gapsCookie", context.gaps_cookie); |
| |
| UpdateAuthParams(¶ms, IsRestrictiveProxy()); |
| |
| GaiaScreenMode screen_mode = GetGaiaScreenMode(context.email, |
| context.use_offline); |
| params.SetInteger("screenMode", screen_mode); |
| |
| if (screen_mode == GAIA_SCREEN_MODE_AD && !authpolicy_login_helper_) |
| authpolicy_login_helper_ = std::make_unique<AuthPolicyLoginHelper>(); |
| |
| if (screen_mode != GAIA_SCREEN_MODE_OFFLINE) { |
| const std::string app_locale = g_browser_process->GetApplicationLocale(); |
| if (!app_locale.empty()) |
| params.SetString("hl", app_locale); |
| } |
| |
| std::string realm(GetRealm()); |
| if (!realm.empty()) { |
| params.SetString("realm", realm); |
| } |
| |
| const std::string enterprise_display_domain(GetEnterpriseDisplayDomain()); |
| const std::string enterprise_enrollment_domain( |
| GetEnterpriseEnrollmentDomain()); |
| if (!enterprise_display_domain.empty()) |
| params.SetString("enterpriseDisplayDomain", enterprise_display_domain); |
| if (!enterprise_enrollment_domain.empty()) { |
| params.SetString("enterpriseEnrollmentDomain", |
| enterprise_enrollment_domain); |
| } |
| params.SetBoolean("enterpriseManagedDevice", |
| g_browser_process->platform_part() |
| ->browser_policy_connector_chromeos() |
| ->IsEnterpriseManaged()); |
| const AccountId& owner_account_id = |
| user_manager::UserManager::Get()->GetOwnerAccountId(); |
| params.SetBoolean("hasDeviceOwner", owner_account_id.is_valid()); |
| if (owner_account_id.is_valid()) { |
| // Some Autotest policy tests appear to wipe the user list in Local State |
| // but preserve a policy file referencing an owner: https://crbug.com/850139 |
| const user_manager::User* owner_user = |
| user_manager::UserManager::Get()->FindUser(owner_account_id); |
| if (owner_user && |
| owner_user->GetType() == user_manager::UserType::USER_TYPE_CHILD) { |
| params.SetString("obfuscatedOwnerId", owner_account_id.GetGaiaId()); |
| } |
| } |
| |
| params.SetString("chromeType", GetChromeType()); |
| params.SetString("clientId", |
| GaiaUrls::GetInstance()->oauth2_chrome_client_id()); |
| params.SetString("clientVersion", version_info::GetVersionNumber()); |
| if (!platform_version->empty()) |
| params.SetString("platformVersion", *platform_version); |
| params.SetString("releaseChannel", chrome::GetChannelName()); |
| params.SetString("endpointGen", kEndpointGen); |
| |
| std::string email_domain; |
| if (CrosSettings::Get()->GetString(kAccountsPrefLoginScreenDomainAutoComplete, |
| &email_domain) && |
| !email_domain.empty()) { |
| params.SetString("emailDomain", email_domain); |
| } |
| |
| params.SetString("gaiaUrl", GaiaUrls::GetInstance()->gaia_url().spec()); |
| |
| if (base::CommandLine::ForCurrentProcess()->HasSwitch( |
| switches::kCrosGaiaApiV1)) { |
| params.SetString("chromeOSApiVersion", "1"); |
| } else { |
| // This enables GLIF MM UI for the online Gaia screen by default. |
| // (see https://crbug.com/709244 ). |
| params.SetString("chromeOSApiVersion", "2"); |
| } |
| // We only send |chromeos_board| Gaia URL parameter if user has opted into |
| // sending device statistics. |
| if (*collect_stats_consent) |
| params.SetString("lsbReleaseBoard", base::SysInfo::GetLsbReleaseBoard()); |
| |
| params.SetString("webviewPartitionName", partition_name); |
| |
| frame_state_ = FRAME_STATE_LOADING; |
| CallJS("loadAuthExtension", params); |
| } |
| |
| void GaiaScreenHandler::ReloadGaia(bool force_reload) { |
| if (frame_state_ == FRAME_STATE_LOADING && !force_reload) { |
| VLOG(1) << "Skipping reloading of Gaia since gaia is loading."; |
| return; |
| } |
| NetworkStateInformer::State state = network_state_informer_->state(); |
| if (state != NetworkStateInformer::ONLINE && |
| !signin_screen_handler_->proxy_auth_dialog_need_reload_) { |
| VLOG(1) << "Skipping reloading of Gaia since network state=" |
| << NetworkStateInformer::StatusString(state); |
| return; |
| } |
| |
| signin_screen_handler_->proxy_auth_dialog_need_reload_ = false; |
| VLOG(1) << "Reloading Gaia."; |
| frame_state_ = FRAME_STATE_LOADING; |
| LoadAuthExtension(force_reload, false /* offline */); |
| } |
| |
| void GaiaScreenHandler::MonitorOfflineIdle(bool is_online) { |
| CallJS("monitorOfflineIdle", is_online); |
| } |
| |
| void GaiaScreenHandler::DeclareLocalizedValues( |
| ::login::LocalizedValuesBuilder* builder) { |
| builder->Add("signinScreenTitle", IDS_SIGNIN_SCREEN_TITLE_TAB_PROMPT); |
| builder->Add("guestSignin", IDS_BROWSE_WITHOUT_SIGNING_IN_HTML); |
| builder->Add("backButton", IDS_ACCNAME_BACK); |
| builder->Add("closeButton", IDS_CLOSE); |
| builder->Add("whitelistErrorConsumer", IDS_LOGIN_ERROR_WHITELIST); |
| builder->Add("whitelistErrorEnterprise", |
| IDS_ENTERPRISE_LOGIN_ERROR_WHITELIST); |
| builder->Add("tryAgainButton", IDS_WHITELIST_ERROR_TRY_AGAIN_BUTTON); |
| builder->Add("learnMoreButton", IDS_LEARN_MORE); |
| builder->Add("gaiaLoading", IDS_LOGIN_GAIA_LOADING_MESSAGE); |
| |
| // Strings used by the SAML fatal error dialog. |
| builder->Add("fatalErrorMessageNoAccountDetails", |
| IDS_LOGIN_FATAL_ERROR_NO_ACCOUNT_DETAILS); |
| builder->Add("fatalErrorMessageNoPassword", |
| IDS_LOGIN_FATAL_ERROR_NO_PASSWORD); |
| builder->Add("fatalErrorMessageVerificationFailed", |
| IDS_LOGIN_FATAL_ERROR_PASSWORD_VERIFICATION); |
| builder->Add("fatalErrorMessageInsecureURL", |
| IDS_LOGIN_FATAL_ERROR_TEXT_INSECURE_URL); |
| builder->Add("fatalErrorDoneButton", IDS_DONE); |
| builder->Add("fatalErrorTryAgainButton", |
| IDS_LOGIN_FATAL_ERROR_TRY_AGAIN_BUTTON); |
| |
| builder->AddF("loginWelcomeMessage", IDS_LOGIN_WELCOME_MESSAGE, |
| ui::GetChromeOSDeviceTypeResourceId()); |
| builder->Add("offlineLoginEmail", IDS_OFFLINE_LOGIN_EMAIL); |
| builder->Add("offlineLoginPassword", IDS_OFFLINE_LOGIN_PASSWORD); |
| builder->Add("offlineLoginInvalidEmail", IDS_OFFLINE_LOGIN_INVALID_EMAIL); |
| builder->Add("offlineLoginInvalidPassword", |
| IDS_OFFLINE_LOGIN_INVALID_PASSWORD); |
| builder->Add("offlineLoginNextBtn", IDS_OFFLINE_LOGIN_NEXT_BUTTON_TEXT); |
| builder->Add("offlineLoginForgotPasswordBtn", |
| IDS_OFFLINE_LOGIN_FORGOT_PASSWORD_BUTTON_TEXT); |
| builder->Add("offlineLoginForgotPasswordDlg", |
| IDS_OFFLINE_LOGIN_FORGOT_PASSWORD_DIALOG_TEXT); |
| builder->Add("offlineLoginCloseBtn", IDS_OFFLINE_LOGIN_CLOSE_BUTTON_TEXT); |
| builder->Add("enterpriseInfoMessage", IDS_LOGIN_DEVICE_MANAGED_BY_NOTICE); |
| builder->Add("samlInterstitialMessage", |
| IDS_LOGIN_SAML_INTERSTITIAL_MESSAGE); |
| builder->Add("samlInterstitialChangeAccountLink", |
| IDS_LOGIN_SAML_INTERSTITIAL_CHANGE_ACCOUNT_LINK_TEXT); |
| builder->Add("samlInterstitialNextBtn", |
| IDS_LOGIN_SAML_INTERSTITIAL_NEXT_BUTTON_TEXT); |
| |
| builder->Add("adAuthWelcomeMessage", IDS_AD_DOMAIN_AUTH_WELCOME_MESSAGE); |
| builder->Add("adAuthLoginUsername", IDS_AD_AUTH_LOGIN_USER); |
| builder->Add("adLoginPassword", IDS_AD_LOGIN_PASSWORD); |
| |
| builder->Add("adPassChangeOldPasswordHint", |
| IDS_AD_PASSWORD_CHANGE_OLD_PASSWORD_HINT); |
| builder->Add("adPassChangeNewPasswordHint", |
| IDS_AD_PASSWORD_CHANGE_NEW_PASSWORD_HINT); |
| builder->Add("adPassChangeRepeatNewPasswordHint", |
| IDS_AD_PASSWORD_CHANGE_REPEAT_NEW_PASSWORD_HINT); |
| builder->Add("adPassChangeOldPasswordError", |
| IDS_AD_PASSWORD_CHANGE_INVALID_PASSWORD_ERROR); |
| builder->Add("adPassChangeNewPasswordRejected", |
| IDS_AD_PASSWORD_CHANGE_NEW_PASSWORD_REJECTED_SHORT_ERROR); |
| builder->Add("adPassChangePasswordsMismatch", |
| IDS_AD_PASSWORD_CHANGE_PASSWORDS_MISMATCH_ERROR); |
| } |
| |
| void GaiaScreenHandler::Initialize() { |
| } |
| |
| void GaiaScreenHandler::RegisterMessages() { |
| AddCallback("webviewLoadAborted", |
| &GaiaScreenHandler::HandleWebviewLoadAborted); |
| AddCallback("completeLogin", &GaiaScreenHandler::HandleCompleteLogin); |
| AddCallback("completeAuthentication", |
| &GaiaScreenHandler::HandleCompleteAuthentication); |
| AddCallback("usingSAMLAPI", &GaiaScreenHandler::HandleUsingSAMLAPI); |
| AddCallback("scrapedPasswordCount", |
| &GaiaScreenHandler::HandleScrapedPasswordCount); |
| AddCallback("scrapedPasswordVerificationFailed", |
| &GaiaScreenHandler::HandleScrapedPasswordVerificationFailed); |
| AddCallback("loginWebuiReady", &GaiaScreenHandler::HandleGaiaUIReady); |
| AddCallback("identifierEntered", &GaiaScreenHandler::HandleIdentifierEntered); |
| AddCallback("updateOfflineLogin", |
| &GaiaScreenHandler::set_offline_login_is_active); |
| AddCallback("authExtensionLoaded", |
| &GaiaScreenHandler::HandleAuthExtensionLoaded); |
| AddCallback("completeAdAuthentication", |
| &GaiaScreenHandler::HandleCompleteAdAuthentication); |
| AddCallback("cancelAdAuthentication", |
| &GaiaScreenHandler::HandleCancelActiveDirectoryAuth); |
| AddRawCallback("showAddUser", &GaiaScreenHandler::HandleShowAddUser); |
| AddCallback("getIsSamlUserPasswordless", |
| &GaiaScreenHandler::HandleGetIsSamlUserPasswordless); |
| AddCallback("updateOobeDialogSize", |
| &GaiaScreenHandler::HandleUpdateOobeDialogSize); |
| AddCallback("hideOobeDialog", &GaiaScreenHandler::HandleHideOobeDialog); |
| AddCallback("updateSigninUIState", |
| &GaiaScreenHandler::HandleUpdateSigninUIState); |
| AddCallback("showGuestForGaia", |
| &GaiaScreenHandler::HandleShowGuestForGaiaScreen); |
| |
| // Allow UMA metrics collection from JS. |
| web_ui()->AddMessageHandler(std::make_unique<MetricsHandler>()); |
| } |
| |
| void GaiaScreenHandler::OnPortalDetectionCompleted( |
| const NetworkState* network, |
| const NetworkPortalDetector::CaptivePortalState& state) { |
| VLOG(1) << "OnPortalDetectionCompleted " |
| << NetworkPortalDetector::CaptivePortalStatusString(state.status); |
| |
| const NetworkPortalDetector::CaptivePortalStatus previous_status = |
| captive_portal_status_; |
| captive_portal_status_ = state.status; |
| if (offline_login_is_active() || |
| IsOnline(captive_portal_status_) == IsOnline(previous_status) || |
| disable_restrictive_proxy_check_for_test_ || |
| GetCurrentScreen() != kScreenId) |
| return; |
| |
| LoadAuthExtension(true /* force */, false /* offline */); |
| } |
| |
| void GaiaScreenHandler::HandleIdentifierEntered(const std::string& user_email) { |
| if (LoginDisplayHost::default_host() && |
| !LoginDisplayHost::default_host()->IsUserWhitelisted( |
| user_manager::known_user::GetAccountId( |
| user_email, std::string() /* id */, AccountType::UNKNOWN))) { |
| ShowWhitelistCheckFailedError(); |
| } |
| } |
| |
| void GaiaScreenHandler::HandleAuthExtensionLoaded() { |
| VLOG(1) << "Auth extension finished loading"; |
| auth_extension_being_loaded_ = false; |
| } |
| |
| void GaiaScreenHandler::HandleWebviewLoadAborted( |
| const std::string& error_reason_str) { |
| // TODO(nkostylev): Switch to int code once webview supports that. |
| // http://crbug.com/470483 |
| if (error_reason_str == "ERR_ABORTED") { |
| LOG(WARNING) << "Ignoring Gaia webview error: " << error_reason_str; |
| return; |
| } |
| |
| // TODO(nkostylev): Switch to int code once webview supports that. |
| // http://crbug.com/470483 |
| // Extract some common codes used by SigninScreenHandler for now. |
| if (error_reason_str == "ERR_NAME_NOT_RESOLVED") |
| frame_error_ = net::ERR_NAME_NOT_RESOLVED; |
| else if (error_reason_str == "ERR_INTERNET_DISCONNECTED") |
| frame_error_ = net::ERR_INTERNET_DISCONNECTED; |
| else if (error_reason_str == "ERR_NETWORK_CHANGED") |
| frame_error_ = net::ERR_NETWORK_CHANGED; |
| else if (error_reason_str == "ERR_INTERNET_DISCONNECTED") |
| frame_error_ = net::ERR_INTERNET_DISCONNECTED; |
| else if (error_reason_str == "ERR_PROXY_CONNECTION_FAILED") |
| frame_error_ = net::ERR_PROXY_CONNECTION_FAILED; |
| else if (error_reason_str == "ERR_TUNNEL_CONNECTION_FAILED") |
| frame_error_ = net::ERR_TUNNEL_CONNECTION_FAILED; |
| else |
| frame_error_ = net::ERR_INTERNET_DISCONNECTED; |
| |
| LOG(ERROR) << "Gaia webview error: " << error_reason_str; |
| NetworkError::ErrorReason error_reason = |
| NetworkError::ERROR_REASON_FRAME_ERROR; |
| frame_state_ = FRAME_STATE_ERROR; |
| UpdateState(error_reason); |
| } |
| |
| AccountId GaiaScreenHandler::GetAccountId( |
| const std::string& authenticated_email, |
| const std::string& id, |
| const AccountType& account_type) const { |
| const std::string canonicalized_email = |
| gaia::CanonicalizeEmail(gaia::SanitizeEmail(authenticated_email)); |
| |
| const AccountId account_id = user_manager::known_user::GetAccountId( |
| authenticated_email, id, account_type); |
| |
| if (account_id.GetUserEmail() != canonicalized_email) { |
| LOG(WARNING) << "Existing user '" << account_id.GetUserEmail() |
| << "' authenticated by alias '" << canonicalized_email << "'."; |
| } |
| |
| return account_id; |
| } |
| |
| void GaiaScreenHandler::DoAdAuth( |
| const std::string& username, |
| const Key& key, |
| authpolicy::ErrorType error, |
| const authpolicy::ActiveDirectoryAccountInfo& account_info) { |
| if (error != authpolicy::ERROR_NONE) |
| authpolicy_login_helper_->CancelRequestsAndRestart(); |
| |
| switch (error) { |
| case authpolicy::ERROR_NONE: { |
| DCHECK(account_info.has_account_id() && |
| !account_info.account_id().empty() && |
| LoginDisplayHost::default_host()); |
| const AccountId account_id(GetAccountId( |
| username, account_info.account_id(), AccountType::ACTIVE_DIRECTORY)); |
| LoginDisplayHost::default_host()->SetDisplayAndGivenName( |
| account_info.display_name(), account_info.given_name()); |
| UserContext user_context( |
| user_manager::UserType::USER_TYPE_ACTIVE_DIRECTORY, account_id); |
| user_context.SetKey(key); |
| user_context.SetAuthFlow(UserContext::AUTH_FLOW_ACTIVE_DIRECTORY); |
| user_context.SetIsUsingOAuth(false); |
| LoginDisplayHost::default_host()->CompleteLogin(user_context); |
| break; |
| } |
| case authpolicy::ERROR_PASSWORD_EXPIRED: |
| DCHECK(active_directory_password_change_screen_handler_); |
| active_directory_password_change_screen_handler_->ShowScreen(username); |
| break; |
| case authpolicy::ERROR_PARSE_UPN_FAILED: |
| case authpolicy::ERROR_BAD_USER_NAME: |
| CallJS("invalidateAd", username, |
| static_cast<int>(ActiveDirectoryErrorState::BAD_USERNAME)); |
| break; |
| case authpolicy::ERROR_BAD_PASSWORD: |
| CallJS("invalidateAd", username, |
| static_cast<int>(ActiveDirectoryErrorState::BAD_AUTH_PASSWORD)); |
| break; |
| default: |
| CallJS("invalidateAd", username, |
| static_cast<int>(ActiveDirectoryErrorState::NONE)); |
| core_oobe_view_->ShowSignInError( |
| 0, GetAdErrorMessage(error), std::string(), |
| HelpAppLauncher::HELP_CANT_ACCESS_ACCOUNT); |
| } |
| } |
| |
| void GaiaScreenHandler::HandleCompleteAdAuthentication( |
| const std::string& username, |
| const std::string& password) { |
| if (LoginDisplayHost::default_host()) |
| LoginDisplayHost::default_host()->SetDisplayEmail(username); |
| |
| set_populated_email(username); |
| DCHECK(authpolicy_login_helper_); |
| authpolicy_login_helper_->AuthenticateUser( |
| username, std::string() /* object_guid */, password, |
| base::BindOnce(&GaiaScreenHandler::DoAdAuth, weak_factory_.GetWeakPtr(), |
| username, Key(password))); |
| } |
| |
| void GaiaScreenHandler::HandleCancelActiveDirectoryAuth() { |
| DCHECK(authpolicy_login_helper_); |
| authpolicy_login_helper_->CancelRequestsAndRestart(); |
| } |
| |
| void GaiaScreenHandler::HandleCompleteAuthentication( |
| const std::string& gaia_id, |
| const std::string& email, |
| const std::string& password, |
| const std::string& auth_code, |
| bool using_saml, |
| const std::string& gaps_cookie, |
| const ::login::StringList& services) { |
| if (!LoginDisplayHost::default_host()) |
| return; |
| |
| DCHECK(!email.empty()); |
| DCHECK(!gaia_id.empty()); |
| const std::string sanitized_email = gaia::SanitizeEmail(email); |
| LoginDisplayHost::default_host()->SetDisplayEmail(sanitized_email); |
| |
| const user_manager::UserType user_type = |
| GetUsertypeFromServicesString(services); |
| |
| UserContext user_context(user_type, |
| GetAccountId(email, gaia_id, AccountType::GOOGLE)); |
| user_context.SetKey(Key(password)); |
| // Save the user's plaintext password for possible authentication to a |
| // network. See https://crbug.com/386606 for details. |
| user_context.SetPasswordKey(Key(password)); |
| user_context.SetAuthCode(auth_code); |
| user_context.SetAuthFlow(using_saml |
| ? UserContext::AUTH_FLOW_GAIA_WITH_SAML |
| : UserContext::AUTH_FLOW_GAIA_WITHOUT_SAML); |
| user_context.SetGAPSCookie(gaps_cookie); |
| LoginDisplayHost::default_host()->CompleteLogin(user_context); |
| } |
| |
| void GaiaScreenHandler::HandleCompleteLogin(const std::string& gaia_id, |
| const std::string& typed_email, |
| const std::string& password, |
| bool using_saml) { |
| VLOG(1) << "HandleCompleteLogin"; |
| DoCompleteLogin(gaia_id, typed_email, password, using_saml); |
| } |
| |
| void GaiaScreenHandler::HandleUsingSAMLAPI() { |
| SetSAMLPrincipalsAPIUsed(true); |
| } |
| |
| void GaiaScreenHandler::HandleScrapedPasswordCount(int password_count) { |
| SetSAMLPrincipalsAPIUsed(false); |
| // Use a histogram that has 11 buckets, one for each of the values in [0, 9] |
| // and an overflow bucket at the end. |
| UMA_HISTOGRAM_ENUMERATION( |
| "ChromeOS.SAML.Scraping.PasswordCount", std::min(password_count, 10), 11); |
| if (password_count == 0) |
| HandleScrapedPasswordVerificationFailed(); |
| } |
| |
| void GaiaScreenHandler::HandleScrapedPasswordVerificationFailed() { |
| RecordSAMLScrapingVerificationResultInHistogram(false); |
| } |
| |
| void GaiaScreenHandler::HandleGaiaUIReady() { |
| VLOG(1) << "Gaia is loaded"; |
| |
| // As we could miss and window.onload could already be called, restore |
| // focus to current pod (see crbug/175243). |
| if (gaia_silent_load_) |
| signin_screen_handler_->RefocusCurrentPod(); |
| |
| frame_error_ = net::OK; |
| frame_state_ = FRAME_STATE_LOADED; |
| |
| if (network_state_informer_->state() == NetworkStateInformer::ONLINE) |
| UpdateState(NetworkError::ERROR_REASON_UPDATE); |
| |
| if (test_expects_complete_login_) |
| SubmitLoginFormForTest(); |
| |
| if (LoginDisplayHost::default_host()) |
| LoginDisplayHost::default_host()->OnGaiaScreenReady(); |
| } |
| |
| void GaiaScreenHandler::HandleUpdateOobeDialogSize(int width, int height) { |
| if (LoginDisplayHost::default_host()) |
| LoginDisplayHost::default_host()->UpdateOobeDialogSize(width, height); |
| } |
| |
| void GaiaScreenHandler::HandleHideOobeDialog() { |
| if (LoginDisplayHost::default_host()) |
| LoginDisplayHost::default_host()->HideOobeDialog(); |
| } |
| |
| void GaiaScreenHandler::HandleShowAddUser(const base::ListValue* args) { |
| // TODO(xiaoyinh): Add trace event for gaia webui in views login screen. |
| TRACE_EVENT_ASYNC_STEP_INTO0("ui", "ShowLoginWebUI", |
| LoginDisplayHostWebUI::kShowLoginWebUIid, |
| "ShowAddUser"); |
| |
| std::string email; |
| // |args| can be null if it's OOBE. |
| if (args) |
| args->GetString(0, &email); |
| set_populated_email(email); |
| if (!email.empty()) |
| SendReauthReason(AccountId::FromUserEmail(email)); |
| OnShowAddUser(); |
| } |
| |
| void GaiaScreenHandler::HandleGetIsSamlUserPasswordless( |
| const std::string& callback_id, |
| const std::string& typed_email, |
| const std::string& gaia_id) { |
| AllowJavascript(); |
| // TODO(emaxx,https://crbug.com/826417): Determine the result value based on |
| // known_user properties if the user already existed, or the |
| // DeviceSamlLoginAuthenticationType policy if that's a new user. |
| ResolveJavascriptCallback(base::Value(callback_id), |
| base::Value(false) /* isSamlUserPasswordless */); |
| } |
| |
| void GaiaScreenHandler::HandleUpdateSigninUIState(int state) { |
| if (LoginDisplayHost::default_host()) { |
| auto dialog_state = static_cast<ash::mojom::OobeDialogState>(state); |
| DCHECK(ash::mojom::IsKnownEnumValue(dialog_state)); |
| LoginDisplayHost::default_host()->UpdateOobeDialogState(dialog_state); |
| } |
| } |
| |
| void GaiaScreenHandler::HandleShowGuestForGaiaScreen(bool allow_guest_login, |
| bool can_show_for_gaia) { |
| LoginScreenClient::Get()->login_screen()->SetAllowLoginAsGuest( |
| allow_guest_login); |
| LoginScreenClient::Get()->login_screen()->SetShowGuestButtonForGaiaScreen( |
| can_show_for_gaia); |
| } |
| |
| void GaiaScreenHandler::OnShowAddUser() { |
| signin_screen_handler_->is_account_picker_showing_first_time_ = false; |
| lock_screen_utils::EnforcePolicyInputMethods(std::string()); |
| ShowGaiaAsync(base::nullopt); |
| } |
| |
| void GaiaScreenHandler::DoCompleteLogin(const std::string& gaia_id, |
| const std::string& typed_email, |
| const std::string& password, |
| bool using_saml) { |
| if (!LoginDisplayHost::default_host()) |
| return; |
| |
| if (using_saml && !using_saml_api_) |
| RecordSAMLScrapingVerificationResultInHistogram(true); |
| |
| DCHECK(!typed_email.empty()); |
| DCHECK(!gaia_id.empty()); |
| const std::string sanitized_email = gaia::SanitizeEmail(typed_email); |
| LoginDisplayHost::default_host()->SetDisplayEmail(sanitized_email); |
| const AccountId account_id = |
| GetAccountId(typed_email, gaia_id, AccountType::GOOGLE); |
| const user_manager::User* const user = |
| user_manager::UserManager::Get()->FindUser(account_id); |
| |
| UserContext user_context = |
| user ? UserContext(*user) |
| : UserContext(CalculateUserType(account_id), account_id); |
| user_context.SetKey(Key(password)); |
| // Save the user's plaintext password for possible authentication to a |
| // network. If the user's OpenNetworkConfiguration policy contains a |
| // ${PASSWORD} variable, then the user's password will be used to authenticate |
| // to the specified network. |
| // |
| // The user's password needs to be saved in memory until the policy can be |
| // examined. When the policy comes in, if it does not contain the ${PASSWORD} |
| // variable, the user's password will be discarded. If it contains the |
| // password, it will be sent to the session manager, which will then save it |
| // in a keyring so it can be retrieved for authenticating to the network. |
| // |
| // More details can be found in https://crbug.com/386606 |
| user_context.SetPasswordKey(Key(password)); |
| user_context.SetAuthFlow(using_saml |
| ? UserContext::AUTH_FLOW_GAIA_WITH_SAML |
| : UserContext::AUTH_FLOW_GAIA_WITHOUT_SAML); |
| LoginDisplayHost::default_host()->CompleteLogin(user_context); |
| |
| if (test_expects_complete_login_) { |
| VLOG(2) << "Complete test login for " << typed_email |
| << ", requested=" << test_user_; |
| |
| test_expects_complete_login_ = false; |
| test_user_.clear(); |
| test_pass_.clear(); |
| } |
| } |
| |
| void GaiaScreenHandler::StartClearingDnsCache() { |
| if (dns_clear_task_running_ || |
| !g_browser_process->system_network_context_manager()) { |
| return; |
| } |
| |
| dns_cleared_ = false; |
| |
| g_browser_process->system_network_context_manager() |
| ->GetContext() |
| ->ClearHostCache(nullptr /* filter */, |
| // Need to ensure that even if the network service |
| // crashes, OnDnsCleared() is invoked. |
| mojo::WrapCallbackWithDropHandler( |
| base::BindOnce(&GaiaScreenHandler::OnDnsCleared, |
| weak_factory_.GetWeakPtr()), |
| base::BindOnce(&GaiaScreenHandler::OnDnsCleared, |
| weak_factory_.GetWeakPtr()))); |
| dns_clear_task_running_ = true; |
| } |
| |
| void GaiaScreenHandler::OnDnsCleared() { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| dns_clear_task_running_ = false; |
| dns_cleared_ = true; |
| ShowGaiaScreenIfReady(); |
| } |
| |
| void GaiaScreenHandler::StartClearingCookies( |
| const base::Closure& on_clear_callback) { |
| cookies_cleared_ = false; |
| ProfileHelper* profile_helper = ProfileHelper::Get(); |
| LOG_ASSERT(Profile::FromWebUI(web_ui()) == |
| profile_helper->GetSigninProfile()); |
| profile_helper->ClearSigninProfile( |
| base::Bind(&GaiaScreenHandler::OnCookiesCleared, |
| weak_factory_.GetWeakPtr(), on_clear_callback)); |
| } |
| |
| void GaiaScreenHandler::OnCookiesCleared( |
| const base::Closure& on_clear_callback) { |
| DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| cookies_cleared_ = true; |
| on_clear_callback.Run(); |
| } |
| |
| void GaiaScreenHandler::SubmitLoginFormForTest() { |
| VLOG(2) << "Submit login form for test, user=" << test_user_; |
| |
| content::RenderFrameHost* frame = |
| signin::GetAuthFrame(web_ui()->GetWebContents(), kAuthIframeParentName); |
| |
| std::string code = |
| "document.getElementById('identifier').value = '" + test_user_ + "';" |
| "document.getElementById('nextButton').click();"; |
| frame->ExecuteJavaScriptForTests(base::ASCIIToUTF16(code)); |
| |
| if (!test_services_.empty()) { |
| // Prefix each doublequote with backslash, so that it will remain correct |
| // JSON after assigning to the element property. |
| std::string escaped_services; |
| base::ReplaceChars(test_services_, "\"", "\\\"", &escaped_services); |
| code = "document.getElementById('services').value = \"" + escaped_services + |
| "\";"; |
| frame->ExecuteJavaScriptForTests(base::ASCIIToUTF16(code)); |
| } |
| |
| if (!test_pass_.empty()) { |
| code = "document.getElementById('password').value = '" + test_pass_ + "';"; |
| code += "document.getElementById('nextButton').click();"; |
| frame->ExecuteJavaScriptForTests(base::ASCIIToUTF16(code)); |
| } |
| |
| // Test properties are cleared in HandleCompleteLogin because the form |
| // submission might fail and login will not be attempted after reloading |
| // if they are cleared here. |
| } |
| |
| void GaiaScreenHandler::SetSAMLPrincipalsAPIUsed(bool api_used) { |
| using_saml_api_ = api_used; |
| UMA_HISTOGRAM_BOOLEAN("ChromeOS.SAML.APIUsed", api_used); |
| } |
| |
| void GaiaScreenHandler::ShowGaiaAsync( |
| const base::Optional<AccountId>& account_id) { |
| if (account_id) |
| populated_email_ = account_id->GetUserEmail(); |
| show_when_dns_and_cookies_cleared_ = true; |
| if (gaia_silent_load_ && populated_email_.empty()) { |
| dns_cleared_ = true; |
| cookies_cleared_ = true; |
| ShowGaiaScreenIfReady(); |
| } else { |
| StartClearingDnsCache(); |
| StartClearingCookies(base::Bind(&GaiaScreenHandler::ShowGaiaScreenIfReady, |
| weak_factory_.GetWeakPtr())); |
| } |
| } |
| |
| void GaiaScreenHandler::ShowSigninScreenForTest(const std::string& username, |
| const std::string& password, |
| const std::string& services) { |
| VLOG(2) << "ShowSigninScreenForTest for user " << username |
| << ", frame_state=" << frame_state(); |
| |
| test_user_ = username; |
| test_pass_ = password; |
| test_services_ = services; |
| test_expects_complete_login_ = true; |
| |
| // Submit login form for test if gaia is ready. If gaia is loading, login |
| // will be attempted in HandleLoginWebuiReady after gaia is ready. Otherwise, |
| // reload gaia then follow the loading case. |
| if (frame_state() == GaiaScreenHandler::FRAME_STATE_LOADED) { |
| SubmitLoginFormForTest(); |
| } else if (frame_state() != GaiaScreenHandler::FRAME_STATE_LOADING) { |
| OnShowAddUser(); |
| } |
| } |
| |
| void GaiaScreenHandler::CancelShowGaiaAsync() { |
| show_when_dns_and_cookies_cleared_ = false; |
| } |
| |
| void GaiaScreenHandler::ShowGaiaScreenIfReady() { |
| if (!dns_cleared_ || !cookies_cleared_ || |
| !show_when_dns_and_cookies_cleared_ || |
| !LoginDisplayHost::default_host()) { |
| return; |
| } |
| |
| std::string active_network_path = network_state_informer_->network_path(); |
| if (gaia_silent_load_ && |
| (network_state_informer_->state() != NetworkStateInformer::ONLINE || |
| gaia_silent_load_network_ != active_network_path)) { |
| // Network has changed. Force Gaia reload. |
| gaia_silent_load_ = false; |
| } |
| |
| // Views-based login may reach here while pre-loading the Gaia screen, so |
| // update the wallpaper in |LoginDisplayHostMojo::UpdateGaiaDialogVisibility| |
| // instead, which controls the actual visibility of the Gaia screen. |
| if (!ash::features::IsViewsLoginEnabled()) { |
| // Note that LoadAuthExtension clears |populated_email_|. |
| if (populated_email_.empty()) { |
| LoginDisplayHost::default_host()->LoadSigninWallpaper(); |
| } else { |
| LoginDisplayHost::default_host()->LoadWallpaper( |
| user_manager::known_user::GetAccountId( |
| populated_email_, std::string() /* id */, AccountType::UNKNOWN)); |
| } |
| } |
| |
| input_method::InputMethodManager* imm = |
| input_method::InputMethodManager::Get(); |
| |
| scoped_refptr<input_method::InputMethodManager::State> gaia_ime_state = |
| imm->GetActiveIMEState()->Clone(); |
| imm->SetState(gaia_ime_state); |
| |
| // Set Least Recently Used input method for the user. |
| if (!populated_email_.empty()) { |
| lock_screen_utils::SetUserInputMethod(populated_email_, |
| gaia_ime_state.get()); |
| } else { |
| std::vector<std::string> input_methods; |
| if (gaia_ime_state->GetAllowedInputMethods().empty()) { |
| input_methods = |
| imm->GetInputMethodUtil()->GetHardwareLoginInputMethodIds(); |
| } else { |
| input_methods = gaia_ime_state->GetAllowedInputMethods(); |
| } |
| const std::string owner_im = lock_screen_utils::GetUserLastInputMethod( |
| user_manager::UserManager::Get()->GetOwnerAccountId().GetUserEmail()); |
| const std::string system_im = g_browser_process->local_state()->GetString( |
| language_prefs::kPreferredKeyboardLayout); |
| |
| PushFrontIMIfNotExists(owner_im, &input_methods); |
| PushFrontIMIfNotExists(system_im, &input_methods); |
| |
| gaia_ime_state->EnableLoginLayouts( |
| g_browser_process->GetApplicationLocale(), input_methods); |
| |
| if (!system_im.empty()) { |
| gaia_ime_state->ChangeInputMethod(system_im, false /* show_message */); |
| } else if (!owner_im.empty()) { |
| gaia_ime_state->ChangeInputMethod(owner_im, false /* show_message */); |
| } |
| } |
| |
| if (!untrusted_authority_certs_cache_) { |
| // Make additional untrusted authority certificates available for client |
| // certificate discovery in case a SAML flow is used which requires a client |
| // certificate to be present. |
| // When the WebUI is destroyed, |untrusted_authority_certs_cache_| will go |
| // out of scope and the certificates will not be held in memory anymore. |
| untrusted_authority_certs_cache_ = |
| std::make_unique<policy::TempCertsCacheNSS>( |
| g_browser_process->platform_part() |
| ->browser_policy_connector_chromeos() |
| ->GetDeviceNetworkConfigurationUpdater() |
| ->GetAllAuthorityCertificates()); |
| } |
| |
| LoadAuthExtension(!gaia_silent_load_ /* force */, false /* offline */); |
| signin_screen_handler_->UpdateUIState( |
| SigninScreenHandler::UI_STATE_GAIA_SIGNIN, nullptr); |
| core_oobe_view_->UpdateKeyboardState(); |
| |
| if (gaia_silent_load_) { |
| // The variable is assigned to false because silently loaded Gaia page was |
| // used. |
| gaia_silent_load_ = false; |
| } |
| UpdateState(NetworkError::ERROR_REASON_UPDATE); |
| |
| if (core_oobe_view_) { |
| PrefService* prefs = g_browser_process->local_state(); |
| if (prefs->GetBoolean(prefs::kFactoryResetRequested)) { |
| core_oobe_view_->ShowDeviceResetScreen(); |
| } else if (prefs->GetBoolean(prefs::kDebuggingFeaturesRequested)) { |
| core_oobe_view_->ShowEnableDebuggingScreen(); |
| } |
| } |
| } |
| |
| void GaiaScreenHandler::ShowWhitelistCheckFailedError() { |
| base::DictionaryValue params; |
| params.SetBoolean("enterpriseManaged", |
| g_browser_process->platform_part() |
| ->browser_policy_connector_chromeos() |
| ->IsEnterpriseManaged()); |
| CallJS("showWhitelistCheckFailedError", true, params); |
| } |
| |
| void GaiaScreenHandler::LoadAuthExtension(bool force, |
| bool offline) { |
| VLOG(1) << "LoadAuthExtension, force: " << force |
| << ", offline: " << offline; |
| |
| if (auth_extension_being_loaded_) { |
| VLOG(1) << "Skip loading the Auth extension as it's already being loaded"; |
| return; |
| } |
| |
| auth_extension_being_loaded_ = true; |
| GaiaContext context; |
| context.force_reload = force; |
| context.use_offline = offline; |
| context.email = populated_email_; |
| |
| std::string gaia_id; |
| if (!context.email.empty() && |
| user_manager::known_user::FindGaiaID( |
| AccountId::FromUserEmail(context.email), &gaia_id)) { |
| context.gaia_id = gaia_id; |
| } |
| |
| if (!context.email.empty()) { |
| context.gaps_cookie = user_manager::known_user::GetGAPSCookie( |
| AccountId::FromUserEmail(gaia::CanonicalizeEmail(context.email))); |
| } |
| |
| populated_email_.clear(); |
| |
| LoadGaia(context); |
| } |
| |
| void GaiaScreenHandler::UpdateState(NetworkError::ErrorReason reason) { |
| if (signin_screen_handler_) |
| signin_screen_handler_->UpdateState(reason); |
| } |
| |
| bool GaiaScreenHandler::IsRestrictiveProxy() const { |
| return !disable_restrictive_proxy_check_for_test_ && |
| !IsOnline(captive_portal_status_); |
| } |
| |
| } // namespace chromeos |