diff options
author | tengs <tengs@chromium.org> | 2014-11-03 17:42:32 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-04 01:42:52 +0000 |
commit | 174ab92a101d02bce1301d8fdc8ec15ec5557137 (patch) | |
tree | e993504239c95c5d2b7fb214ca7a6c61b0e03030 | |
parent | 72641dc61a1966ccc9e63cee95aec1e6136044a2 (diff) | |
download | chromium_src-174ab92a101d02bce1301d8fdc8ec15ec5557137.zip chromium_src-174ab92a101d02bce1301d8fdc8ec15ec5557137.tar.gz chromium_src-174ab92a101d02bce1301d8fdc8ec15ec5557137.tar.bz2 |
Reauthenticate the user before launching Smart Lock setup app.
The reauth is needed to acquire the user's password to add a new cryptohome
key for sign-in.
BUG=409427
Review URL: https://codereview.chromium.org/668213003
Cr-Commit-Position: refs/heads/master@{#302541}
13 files changed, 395 insertions, 16 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 07f06be..3a3bc47 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -14889,6 +14889,9 @@ Do you accept? <message name="IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_LOGIN_FAILURE" desc="Tooltip text shown on a user's lock screen when Smart Lock signin attempt fails."> Smart Lock couldn't verify your account. Type your password to enter. </message> + <message name="IDS_SMART_LOCK_SCREENLOCK_TOOLTIP_HARDLOCK_REAUTH_USER" desc="Tooltip text shown on a user's lock screen pod to reauthenticate the user before setting up Smart Lock. A password has to be entered to unlock the device."> + To set up Chrome Smart Lock, Google needs to make sure it's you--type your password to get started. + </message> <message name="IDS_EASY_UNLOCK_SCREENLOCK_USER_POD_AUTH_VALUE" desc="Message on lock screen user pod shown in place of password field when Easy Unlock is enabled and a phone that can unlock the Chromebook is detected in proximity."> Click to enter </message> diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc new file mode 100644 index 0000000..a19360d --- /dev/null +++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc @@ -0,0 +1,130 @@ +// 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 "base/bind.h" +#include "base/message_loop/message_loop.h" +#include "chrome/browser/chrome_notification_types.h" +#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h" +#include "chrome/browser/chromeos/login/lock/screen_locker.h" +#include "chrome/browser/signin/screenlock_bridge.h" +#include "chrome/grit/generated_resources.h" +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/session_manager_client.h" +#include "chromeos/login/auth/auth_status_consumer.h" +#include "chromeos/login/auth/user_context.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/notification_service.h" +#include "ui/base/l10n/l10n_util.h" + +namespace chromeos { + +namespace { + +void EndReauthAttempt(); + +// Performs the actual reauth flow and returns the user context it obtains. +class ReauthHandler : public content::NotificationObserver, + public chromeos::AuthStatusConsumer { + public: + explicit ReauthHandler(EasyUnlockReauth::UserContextCallback callback) + : callback_(callback) {} + + virtual ~ReauthHandler() {} + + bool Start() { + ScreenLocker* screen_locker = ScreenLocker::default_screen_locker(); + if (screen_locker && screen_locker->locked()) { + NOTREACHED(); + return false; + } + + user_manager::UserManager* user_manager = user_manager::UserManager::Get(); + if (user_manager->GetPrimaryUser() != user_manager->GetActiveUser() || + user_manager->GetUnlockUsers().size() != 1) { + LOG(WARNING) << "Only primary users in non-multiprofile sessions are " + << "currently supported for reauth."; + return false; + } + + notification_registrar_.Add(this, + chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, + content::NotificationService::AllSources()); + + SessionManagerClient* session_manager = + chromeos::DBusThreadManager::Get()->GetSessionManagerClient(); + session_manager->RequestLockScreen(); + return true; + } + + // content::NotificationObserver + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override { + CHECK(type == chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED); + bool is_screen_locked = *content::Details<bool>(details).ptr(); + DCHECK(is_screen_locked); + notification_registrar_.RemoveAll(); + + // TODO(tengs): Add an explicit reauth state to the locker and account + // picker, so we can customize the UI. + ScreenLocker* screen_locker = ScreenLocker::default_screen_locker(); + screen_locker->SetLoginStatusConsumer(this); + + // Show tooltip explaining reauth. + ScreenlockBridge::UserPodCustomIconOptions icon_options; + icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE); + icon_options.SetTooltip( + l10n_util::GetStringUTF16( + IDS_SMART_LOCK_SCREENLOCK_TOOLTIP_HARDLOCK_REAUTH_USER), + true); + + const user_manager::UserList& lock_users = screen_locker->users(); + DCHECK(lock_users.size() == 1); + ScreenlockBridge::Get()->lock_handler()->ShowUserPodCustomIcon( + lock_users[0]->email(), icon_options); + } + + // chromeos::AuthStatusConsumer: + virtual void OnAuthSuccess( + const chromeos::UserContext& user_context) override { + callback_.Run(user_context); + // Schedule deletion. + base::MessageLoopForUI::current()->PostTask(FROM_HERE, + base::Bind(&EndReauthAttempt)); + } + + virtual void OnAuthFailure(const chromeos::AuthFailure& error) override {} + + private: + content::NotificationRegistrar notification_registrar_; + EasyUnlockReauth::UserContextCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(ReauthHandler); +}; + +ReauthHandler* g_reauth_handler = NULL; + +void EndReauthAttempt() { + DCHECK(base::MessageLoopForUI::IsCurrent()); + DCHECK(g_reauth_handler); + delete g_reauth_handler; + g_reauth_handler = NULL; +} + +} // namespace + +// static. +bool EasyUnlockReauth::ReauthForUserContext( + base::Callback<void(const UserContext&)> callback) { + DCHECK(base::MessageLoopForUI::IsCurrent()); + if (g_reauth_handler) + return false; + + g_reauth_handler = new ReauthHandler(callback); + return g_reauth_handler->Start(); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h new file mode 100644 index 0000000..041dc87 --- /dev/null +++ b/chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h @@ -0,0 +1,31 @@ +// 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. + +#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_EASY_UNLOCK_REAUTH_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_EASY_UNLOCK_REAUTH_H_ + +#include "base/callback_forward.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" + +namespace chromeos { + +class UserContext; + +// Responsible for locking the screen and reauthenticating the user so we can +// create new cryptohome keys for passwordless sign-in. +class EasyUnlockReauth { + public: + typedef base::Callback<void(const UserContext&)> UserContextCallback; + + // Launches the reauth screen to get the user context. If the screen fails + // for some reason, then this function will return false. + static bool ReauthForUserContext(UserContextCallback callback); + + DISALLOW_IMPLICIT_CONSTRUCTORS(EasyUnlockReauth); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_EASY_UNLOCK_REAUTH_H_ diff --git a/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc b/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc new file mode 100644 index 0000000..41283cc --- /dev/null +++ b/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.cc @@ -0,0 +1,55 @@ +// 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/chromeos/login/easy_unlock/short_lived_user_context.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/task_runner.h" +#include "chrome/common/extensions/extension_constants.h" +#include "chromeos/login/auth/user_context.h" + +namespace chromeos { + +namespace { + +// The number of minutes that the user context will be stored. +const int64 kUserContextTimeToLiveMinutes = 10; + +} // namespace + +ShortLivedUserContext::ShortLivedUserContext( + const UserContext& user_context, + apps::AppLifetimeMonitor* app_lifetime_monitor, + base::TaskRunner* task_runner) + : user_context_(new UserContext(user_context)), + app_lifetime_monitor_(app_lifetime_monitor), + weak_ptr_factory_(this) { + app_lifetime_monitor_->AddObserver(this); + + task_runner->PostDelayedTask( + FROM_HERE, + base::Bind(&ShortLivedUserContext::Reset, weak_ptr_factory_.GetWeakPtr()), + base::TimeDelta::FromMinutes(kUserContextTimeToLiveMinutes)); +} + +ShortLivedUserContext::~ShortLivedUserContext() { + Reset(); +} + +void ShortLivedUserContext::Reset() { + if (user_context_.get()) { + user_context_->ClearSecrets(); + user_context_.reset(); + app_lifetime_monitor_->RemoveObserver(this); + } +} + +void ShortLivedUserContext::OnAppDeactivated(Profile* profile, + const std::string& app_id) { + if (app_id == extension_misc::kEasyUnlockAppId) + Reset(); +} + +} // namespace chromeos diff --git a/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.h b/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.h new file mode 100644 index 0000000..7e4bdabc --- /dev/null +++ b/chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.h @@ -0,0 +1,53 @@ +// 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. + +#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_SHORT_LIVED_USER_CONTEXT_H_ +#define CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_SHORT_LIVED_USER_CONTEXT_H_ + +#include "apps/app_lifetime_monitor.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" + +namespace base { +class TaskRunner; +} + +namespace chromeos { + +class UserContext; + +// Stores the UserContext of an authentication operation on the sign-in/lock +// screen, which is used to generate the keys for Easy Sign-in. +// The lifetime of the user context is bound the the setup app window. As a +// fail-safe, the user context will also be deleted after a set period of time +// in case the app is left open indefintely. +class ShortLivedUserContext : public apps::AppLifetimeMonitor::Observer { + public: + ShortLivedUserContext(const UserContext& user_context, + apps::AppLifetimeMonitor* app_lifetime_monitor, + base::TaskRunner* task_runner); + virtual ~ShortLivedUserContext(); + + // The UserContext returned here can be NULL if its time-to-live has expired. + UserContext* user_context() { return user_context_.get(); } + + private: + void Reset(); + + // apps::AppLifetimeMonitor::Observer: + virtual void OnAppDeactivated(Profile* profile, + const std::string& app_id) override; + + scoped_ptr<UserContext> user_context_; + + apps::AppLifetimeMonitor* app_lifetime_monitor_; + + base::WeakPtrFactory<ShortLivedUserContext> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(ShortLivedUserContext); +}; + +} // namespace chromeos + +#endif // CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_SHORT_LIVED_USER_CONTEXT_H_ diff --git a/chrome/browser/signin/easy_unlock_service.cc b/chrome/browser/signin/easy_unlock_service.cc index cb498dd..6144119 100644 --- a/chrome/browser/signin/easy_unlock_service.cc +++ b/chrome/browser/signin/easy_unlock_service.cc @@ -383,7 +383,7 @@ void EasyUnlockService::CheckCryptohomeKeysAndMaybeHardlock() { chromeos::EasyUnlockKeyManager::RemoteDeviceListToDeviceDataList( *device_list, &parsed_paired); for (const auto& device_key_data : parsed_paired) - paired_devices.insert(device_key_data.public_key); + paired_devices.insert(device_key_data.psk); } if (paired_devices.empty()) { SetHardlockState(EasyUnlockScreenlockStateHandler::NO_PAIRING); @@ -618,7 +618,7 @@ void EasyUnlockService::OnCryptohomeKeysFetchedForChecking( std::set<std::string> devices_in_cryptohome; for (const auto& device_key_data : key_data_list) - devices_in_cryptohome.insert(device_key_data.public_key); + devices_in_cryptohome.insert(device_key_data.psk); if (paired_devices != devices_in_cryptohome || GetHardlockState() == EasyUnlockScreenlockStateHandler::NO_PAIRING) { diff --git a/chrome/browser/signin/easy_unlock_service.h b/chrome/browser/signin/easy_unlock_service.h index 1f256a1..ade435b 100644 --- a/chrome/browser/signin/easy_unlock_service.h +++ b/chrome/browser/signin/easy_unlock_service.h @@ -215,6 +215,12 @@ class EasyUnlockService : public KeyedService { return screenlock_state_handler_.get(); } + // Saves hardlock state for the given user. Update UI if the currently + // associated user is the same. + void SetHardlockStateForUser( + const std::string& user_id, + EasyUnlockScreenlockStateHandler::HardlockState state); + private: // A class to detect whether a bluetooth adapter is present. class BluetoothDetector; @@ -231,12 +237,6 @@ class EasyUnlockService : public KeyedService { // Callback when Bluetooth adapter present state changes. void OnBluetoothAdapterPresentChanged(); - // Saves hardlock state for the given user. Update UI if the currently - // associated user is the same. - void SetHardlockStateForUser( - const std::string& user_id, - EasyUnlockScreenlockStateHandler::HardlockState state); - #if defined(OS_CHROMEOS) // Callback for get key operation from CheckCryptohomeKeysAndMaybeHardlock. void OnCryptohomeKeysFetchedForChecking( diff --git a/chrome/browser/signin/easy_unlock_service_regular.cc b/chrome/browser/signin/easy_unlock_service_regular.cc index 870d663..fb027f3 100644 --- a/chrome/browser/signin/easy_unlock_service_regular.cc +++ b/chrome/browser/signin/easy_unlock_service_regular.cc @@ -18,9 +18,15 @@ #include "chrome/common/extensions/extension_constants.h" #include "chrome/common/pref_names.h" #include "components/pref_registry/pref_registry_syncable.h" +#include "content/public/browser/browser_thread.h" #include "extensions/browser/extension_system.h" #if defined(OS_CHROMEOS) +#include "apps/app_lifetime_monitor_factory.h" +#include "base/thread_task_runner_handle.h" +#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h" +#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_reauth.h" +#include "chrome/browser/chromeos/login/session/user_session_manager.h" #include "chrome/browser/chromeos/profiles/profile_helper.h" #include "components/user_manager/user_manager.h" #endif @@ -40,7 +46,8 @@ const char kKeyPhoneId[] = "permitRecord.id"; EasyUnlockServiceRegular::EasyUnlockServiceRegular(Profile* profile) : EasyUnlockService(profile), - turn_off_flow_status_(EasyUnlockService::IDLE) { + turn_off_flow_status_(EasyUnlockService::IDLE), + weak_ptr_factory_(this) { } EasyUnlockServiceRegular::~EasyUnlockServiceRegular() { @@ -55,6 +62,52 @@ std::string EasyUnlockServiceRegular::GetUserEmail() const { } void EasyUnlockServiceRegular::LaunchSetup() { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); +#if defined(OS_CHROMEOS) + // Force the user to reauthenticate by showing a modal overlay (similar to the + // lock screen). The password obtained from the reauth is cached for a short + // period of time and used to create the cryptohome keys for sign-in. + if (short_lived_user_context_ && short_lived_user_context_->user_context()) { + OpenSetupApp(); + } else { + bool reauth_success = chromeos::EasyUnlockReauth::ReauthForUserContext( + base::Bind(&EasyUnlockServiceRegular::OnUserContextFromReauth, + weak_ptr_factory_.GetWeakPtr())); + if (!reauth_success) + OpenSetupApp(); + } +#else + OpenSetupApp(); +#endif +} + +#if defined(OS_CHROMEOS) +void EasyUnlockServiceRegular::OnUserContextFromReauth( + const chromeos::UserContext& user_context) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + short_lived_user_context_.reset(new chromeos::ShortLivedUserContext( + user_context, apps::AppLifetimeMonitorFactory::GetForProfile(profile()), + base::ThreadTaskRunnerHandle::Get().get())); + + OpenSetupApp(); +} + +void EasyUnlockServiceRegular::OnKeysRefreshedForSetDevices(bool success) { + // If the keys were refreshed successfully, the hardlock state should be + // cleared, so Smart Lock can be used normally. Otherwise, we fall back to + // a hardlock state to force the user to type in their credentials again. + if (success) { + SetHardlockStateForUser(GetUserEmail(), + EasyUnlockScreenlockStateHandler::NO_HARDLOCK); + } + + // Even if the keys refresh suceeded, we still fetch the cryptohome keys as a + // sanity check. + CheckCryptohomeKeysAndMaybeHardlock(); +} +#endif + +void EasyUnlockServiceRegular::OpenSetupApp() { ExtensionService* service = extensions::ExtensionSystem::Get(profile())->extension_service(); const extensions::Extension* extension = @@ -103,7 +156,29 @@ void EasyUnlockServiceRegular::SetRemoteDevices( DictionaryPrefUpdate pairing_update(profile()->GetPrefs(), prefs::kEasyUnlockPairing); pairing_update->SetWithoutPathExpansion(kKeyDevices, devices.DeepCopy()); + +#if defined(OS_CHROMEOS) + // TODO(tengs): Investigate if we can determine if the remote devices were set + // from sync or from the setup app. + if (short_lived_user_context_ && short_lived_user_context_->user_context() && + !devices.empty()) { + // We may already have the password cached, so proceed to create the + // cryptohome keys for sign-in or the system will be hardlocked. + chromeos::UserContext* user_context = + short_lived_user_context_->user_context(); + chromeos::EasyUnlockKeyManager* key_manager = + chromeos::UserSessionManager::GetInstance()->GetEasyUnlockKeyManager(); + + key_manager->RefreshKeys( + *user_context, devices, + base::Bind(&EasyUnlockServiceRegular::OnKeysRefreshedForSetDevices, + weak_ptr_factory_.GetWeakPtr())); + } else { + CheckCryptohomeKeysAndMaybeHardlock(); + } +#else CheckCryptohomeKeysAndMaybeHardlock(); +#endif } void EasyUnlockServiceRegular::ClearRemoteDevices() { @@ -184,6 +259,10 @@ void EasyUnlockServiceRegular::InitializeInternal() { } void EasyUnlockServiceRegular::ShutdownInternal() { +#if defined(OS_CHROMEOS) + short_lived_user_context_.reset(); +#endif + turn_off_flow_.reset(); turn_off_flow_status_ = EasyUnlockService::IDLE; registrar_.RemoveAll(); diff --git a/chrome/browser/signin/easy_unlock_service_regular.h b/chrome/browser/signin/easy_unlock_service_regular.h index 749b583..3a48585 100644 --- a/chrome/browser/signin/easy_unlock_service_regular.h +++ b/chrome/browser/signin/easy_unlock_service_regular.h @@ -12,6 +12,10 @@ #include "base/prefs/pref_change_registrar.h" #include "chrome/browser/signin/easy_unlock_service.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/login/easy_unlock/short_lived_user_context.h" +#endif + namespace base { class DictionaryValue; class ListValue; @@ -50,6 +54,9 @@ class EasyUnlockServiceRegular : public EasyUnlockService { void ShutdownInternal() override; bool IsAllowedInternal() override; + // Opens the component packaged app responsible for setting up Smart Lock. + void OpenSetupApp(); + // Callback when the controlling pref changes. void OnPrefsChanged(); @@ -59,11 +66,20 @@ class EasyUnlockServiceRegular : public EasyUnlockService { // Callback invoked when turn off flow has finished. void OnTurnOffFlowFinished(bool success); +#if defined(OS_CHROMEOS) + void OnUserContextFromReauth(const chromeos::UserContext& user_context); + void OnKeysRefreshedForSetDevices(bool success); + + scoped_ptr<chromeos::ShortLivedUserContext> short_lived_user_context_; +#endif + PrefChangeRegistrar registrar_; TurnOffFlowStatus turn_off_flow_status_; scoped_ptr<EasyUnlockToggleFlow> turn_off_flow_; + base::WeakPtrFactory<EasyUnlockServiceRegular> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(EasyUnlockServiceRegular); }; diff --git a/chrome/browser/signin/screenlock_bridge.cc b/chrome/browser/signin/screenlock_bridge.cc index 5fb5192..c2d7224 100644 --- a/chrome/browser/signin/screenlock_bridge.cc +++ b/chrome/browser/signin/screenlock_bridge.cc @@ -62,9 +62,6 @@ scoped_ptr<base::DictionaryValue> ScreenlockBridge::UserPodCustomIconOptions::ToDictionaryValue() const { scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue()); std::string icon_id = GetIdForIcon(icon_); - if (icon_id.empty()) - return result.Pass(); - result->SetString("id", icon_id); if (!tooltip_.empty()) { diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 6c5f84b..2cfb24d 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc @@ -1242,10 +1242,10 @@ void SigninScreenHandler::HandleAccountPickerReady() { is_account_picker_showing_first_time_ = true; gaia_screen_handler_->MaybePreloadAuthExtension(); + ScreenlockBridge::Get()->SetLockHandler(this); if (ScreenLocker::default_screen_locker()) { ScreenLocker::default_screen_locker()->delegate()->OnLockWebUIReady(); } - ScreenlockBridge::Get()->SetLockHandler(this); if (delegate_) delegate_->OnSigninScreenReady(); diff --git a/chrome/chrome_browser_chromeos.gypi b/chrome/chrome_browser_chromeos.gypi index b7bbae8..65b6ee1 100644 --- a/chrome/chrome_browser_chromeos.gypi +++ b/chrome/chrome_browser_chromeos.gypi @@ -429,10 +429,14 @@ 'browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h', 'browser/chromeos/login/easy_unlock/easy_unlock_metrics.cc', 'browser/chromeos/login/easy_unlock/easy_unlock_metrics.h', + 'browser/chromeos/login/easy_unlock/easy_unlock_reauth.cc', + 'browser/chromeos/login/easy_unlock/easy_unlock_reauth.h', 'browser/chromeos/login/easy_unlock/easy_unlock_remove_keys_operation.cc', 'browser/chromeos/login/easy_unlock/easy_unlock_remove_keys_operation.h', 'browser/chromeos/login/easy_unlock/easy_unlock_types.cc', 'browser/chromeos/login/easy_unlock/easy_unlock_types.h', + 'browser/chromeos/login/easy_unlock/short_lived_user_context.cc', + 'browser/chromeos/login/easy_unlock/short_lived_user_context.h', 'browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.cc', 'browser/chromeos/login/easy_unlock/easy_unlock_user_login_flow.h', 'browser/chromeos/login/enrollment/auto_enrollment_check_screen.cc', diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js index 5526f91..fd3778d 100644 --- a/ui/login/account_picker/user_pod_row.js +++ b/ui/login/account_picker/user_pod_row.js @@ -200,6 +200,13 @@ cr.define('login', function() { __proto__: HTMLDivElement.prototype, /** + * The id of the icon being shown. + * @type {string} + * @private + */ + iconId_: '', + + /** * Tooltip to be shown when the user hovers over the icon. The icon * properties may be set so the tooltip is shown automatically when the icon * is updated. The tooltip is shown in a bubble attached to the icon @@ -286,6 +293,7 @@ cr.define('login', function() { * one of the ids listed in {@code UserPodCustomIcon.ICONS}. */ setIcon: function(id) { + this.iconId_ = id; UserPodCustomIcon.ICONS.forEach(function(icon) { this.iconElement.classList.toggle(icon.class, id == icon.id); }, this); @@ -477,7 +485,9 @@ cr.define('login', function() { bubbleContent.textContent = this.tooltip_; /** @const */ var BUBBLE_OFFSET = CUSTOM_ICON_CONTAINER_SIZE / 2; - /** @const */ var BUBBLE_PADDING = 8; + // TODO(tengs): Introduce a special reauth state for the account picker, + // instead of showing the tooltip bubble here (crbug.com/409427). + /** @const */ var BUBBLE_PADDING = 8 + (this.iconId_ ? 0 : 23); $('bubble').showContentForElement(this, cr.ui.Bubble.Attachment.RIGHT, bubbleContent, @@ -2265,10 +2275,11 @@ cr.define('login', function() { return; } - if (!icon.id) + if (!icon.id && !icon.tooltip) return; - pod.customIconElement.setIcon(icon.id); + if (icon.id) + pod.customIconElement.setIcon(icon.id); if (icon.hardlockOnClick) { pod.customIconElement.setInteractive( |