diff options
author | nkostylev@chromium.org <nkostylev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-02 15:50:04 +0000 |
---|---|---|
committer | nkostylev@chromium.org <nkostylev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-12-02 15:50:04 +0000 |
commit | 9ac20a5c0374c5a4c7e190ecb6e1aeb183af51a6 (patch) | |
tree | c7c50d54f23f794f171fdf4b09f1332a4d45fa30 /chrome/browser | |
parent | b5123fe23a4d0f3b72d65e7e4f33a795b172d78d (diff) | |
download | chromium_src-9ac20a5c0374c5a4c7e190ecb6e1aeb183af51a6.zip chromium_src-9ac20a5c0374c5a4c7e190ecb6e1aeb183af51a6.tar.gz chromium_src-9ac20a5c0374c5a4c7e190ecb6e1aeb183af51a6.tar.bz2 |
[cros] Add blocking UI on offline: OK, online auth: fail case.
Using ParallelAuthenticator to test
http://codereview.chromium.org/3442009
BUG=chromium-os:6638
TEST=manual
Review URL: http://codereview.chromium.org/3583013
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@68013 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r-- | chrome/browser/chromeos/login/login_performer.cc | 347 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/login_performer.h | 92 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/parallel_authenticator.cc | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/password_changed_view.cc | 10 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/password_changed_view.h | 4 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/screen_locker.cc | 85 | ||||
-rw-r--r-- | chrome/browser/chromeos/login/screen_locker.h | 15 |
7 files changed, 465 insertions, 92 deletions
diff --git a/chrome/browser/chromeos/login/login_performer.cc b/chrome/browser/chromeos/login/login_performer.cc index 1f10bfb..4c5749b 100644 --- a/chrome/browser/chromeos/login/login_performer.cc +++ b/chrome/browser/chromeos/login/login_performer.cc @@ -4,42 +4,93 @@ #include "chrome/browser/chromeos/login/login_performer.h" +#include <string> + +#include "app/l10n_util.h" +#include "app/resource_bundle.h" #include "base/logging.h" #include "base/message_loop.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/browser_thread.h" #include "chrome/browser/chromeos/boot_times_loader.h" +#include "chrome/browser/chromeos/cros/cros_library.h" +#include "chrome/browser/chromeos/cros/screen_lock_library.h" #include "chrome/browser/chromeos/login/login_utils.h" +#include "chrome/browser/chromeos/login/screen_locker.h" #include "chrome/browser/chromeos/user_cros_settings_provider.h" +#include "chrome/common/notification_service.h" +#include "chrome/common/notification_type.h" #include "chrome/browser/profile.h" #include "chrome/browser/profile_manager.h" +#include "grit/generated_resources.h" namespace chromeos { -namespace { -} // namespace +// Initialize default LoginPerformer. +// static +LoginPerformer* LoginPerformer::default_performer_ = NULL; LoginPerformer::LoginPerformer(Delegate* delegate) : last_login_failure_(LoginFailure::None()), delegate_(delegate), - method_factory_(this) {} + password_changed_(false), + screen_lock_requested_(false), + method_factory_(this) { + DCHECK(default_performer_ == NULL) + << "LoginPerformer should have only one instance."; + default_performer_ = this; +} + +LoginPerformer::~LoginPerformer() { + DVLOG(1) << "Deleting LoginPerformer"; + DCHECK(default_performer_ != NULL) << "Default instance should exist."; + default_performer_ = NULL; +} //////////////////////////////////////////////////////////////////////////////// // LoginPerformer, LoginStatusConsumer implementation: void LoginPerformer::OnLoginFailure(const LoginFailure& failure) { - last_login_failure_ = failure; - if (delegate_) { - captcha_.clear(); - captcha_token_.clear(); - if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED && - failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) { - captcha_token_ = failure.error().captcha().token; - } - delegate_->OnLoginFailure(failure); - } else { - // TODO(nkostylev): Provide blocking UI using ScreenLocker. - } + DVLOG(1) << "failure.reason " << failure.reason(); + DVLOG(1) << "failure.error.state " << failure.error().state(); + + last_login_failure_ = failure; + if (delegate_) { + captcha_.clear(); + captcha_token_.clear(); + if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED && + failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) { + captcha_token_ = failure.error().captcha().token; + } + delegate_->OnLoginFailure(failure); + return; + } + + // Consequent online login failure with blocking UI on. + // No difference between cases whether screen was locked by the user or + // by LoginPerformer. + // Display recoverable error message using ScreenLocker, + // force sign out otherwise. + if (ScreenLocker::default_screen_locker()) { + ResolveLockLoginFailure(); + return; + } + + // Offline auth - OK, online auth - failed. + if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED) { + ResolveInitialNetworkAuthFailure(); + } else if (failure.reason() == LoginFailure::LOGIN_TIMED_OUT) { + VLOG(1) << "Online login timed out. " + << "Granting user access based on offline auth only."; + // ScreenLock is not active, it's ok to delete itself. + MessageLoop::current()->DeleteSoon(FROM_HERE, this); + } else { + // COULD_NOT_MOUNT_CRYPTOHOME, COULD_NOT_MOUNT_TMPFS: + // happens during offline auth only. + // UNLOCK_FAILED is used during normal screen lock case. + // TODO(nkostylev) DATA_REMOVAL_FAILED - ? + NOTREACHED(); + } } void LoginPerformer::OnLoginSuccess( @@ -47,16 +98,35 @@ void LoginPerformer::OnLoginSuccess( const std::string& password, const GaiaAuthConsumer::ClientLoginResult& credentials, bool pending_requests) { + VLOG(1) << "LoginSuccess, pending_requests " << pending_requests; if (delegate_) { delegate_->OnLoginSuccess(username, password, credentials, pending_requests); + // After delegate_->OnLoginSuccess(...) is called, delegate_ releases + // LoginPerformer ownership. LP now manages it's lifetime on its own. + // 2 things could make it exist longer: + // 1. ScreenLock active (pending correct new password input) + // 2. Pending online auth request. if (!pending_requests) MessageLoop::current()->DeleteSoon(FROM_HERE, this); } else { - DCHECK(!pending_requests); - // Online login has succeeded. Delete our instance. + DCHECK(!pending_requests) + << "Pending request w/o delegate_ should not happen!"; + // Online login has succeeded. + // TODO(nkostylev): Execute CookieFetcher->AttemptFetch() here once + // async login is implemented. + // http://crosbug.com/9814 + if (ScreenLocker::default_screen_locker()) { + DVLOG(1) << "Online login OK - unlocking screen."; + RequestScreenUnlock(); + // Do not delete itself just yet, wait for unlock. + // See ResolveScreenUnlocked(). + return; + } + // There's nothing else that's holding LP from deleting itself - + // no ScreenLock, no pending requests. MessageLoop::current()->DeleteSoon(FROM_HERE, this); } } @@ -74,7 +144,12 @@ void LoginPerformer::OnPasswordChangeDetected( if (delegate_) { delegate_->OnPasswordChangeDetected(credentials); } else { - // TODO(nkostylev): Provide blocking UI using ScreenLocker. + last_login_failure_ = + LoginFailure::FromNetworkAuthFailure(GoogleServiceAuthError( + GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS)); + password_changed_ = true; + DVLOG(1) << "Password change detected - locking screen."; + RequestScreenLock(); } } @@ -95,26 +170,53 @@ void LoginPerformer::OnCheckWhiteListCompleted(bool success, } //////////////////////////////////////////////////////////////////////////////// +// LoginPerformer, NotificationObserver implementation: +// + +void LoginPerformer::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + if (type != NotificationType::SCREEN_LOCK_STATE_CHANGED) + return; + + bool is_screen_locked = *Details<bool>(details).ptr(); + if (is_screen_locked) { + if (screen_lock_requested_) { + screen_lock_requested_ = false; + ResolveScreenLocked(); + } + } else { + ResolveScreenUnlocked(); + } +} + +//////////////////////////////////////////////////////////////////////////////// // LoginPerformer, public: void LoginPerformer::Login(const std::string& username, const std::string& password) { username_ = username; password_ = password; - // Must not proceed without signature verification. - UserCrosSettingsProvider user_settings; - bool trusted_setting_available = user_settings.RequestTrustedAllowNewUser( - method_factory_.NewRunnableMethod( - &LoginPerformer::Login, - username, - password)); - if (!trusted_setting_available) { - // Value of AllowNewUser setting is still not verified. - // Another attempt will be invoked after verification completion. - return; + + // Whitelist check is always performed during initial login and + // should not be performed when ScreenLock is active (pending online auth). + if (!ScreenLocker::default_screen_locker()) { + // Must not proceed without signature verification. + UserCrosSettingsProvider user_settings; + bool trusted_setting_available = user_settings.RequestTrustedAllowNewUser( + method_factory_.NewRunnableMethod(&LoginPerformer::Login, + username, + password)); + if (!trusted_setting_available) { + // Value of AllowNewUser setting is still not verified. + // Another attempt will be invoked after verification completion. + return; + } } - if (UserCrosSettingsProvider::cached_allow_new_user()) { - // Starts authentication if guest login is allowed. + + if (ScreenLocker::default_screen_locker() || + UserCrosSettingsProvider::cached_allow_new_user()) { + // Starts authentication if guest login is allowed or online auth pending. StartAuthentication(); } else { // Otherwise, do whitelist check first. @@ -153,19 +255,182 @@ void LoginPerformer::ResyncEncryptedData() { //////////////////////////////////////////////////////////////////////////////// // LoginPerformer, private: +void LoginPerformer::RequestScreenLock() { + DVLOG(1) << "Screen lock requested"; + if (ScreenLocker::default_screen_locker()) { + DVLOG(1) << "Screen already locked"; + ResolveScreenLocked(); + } else { + screen_lock_requested_ = true; + registrar_.Add( + this, + NotificationType::SCREEN_LOCK_STATE_CHANGED, + NotificationService::AllSources()); + chromeos::CrosLibrary::Get()->GetScreenLockLibrary()-> + NotifyScreenLockRequested(); + } +} + +void LoginPerformer::RequestScreenUnlock() { + DVLOG(1) << "Screen unlock requested"; + if (ScreenLocker::default_screen_locker()) { + chromeos::CrosLibrary::Get()->GetScreenLockLibrary()-> + NotifyScreenUnlockRequested(); + // Will unsubscribe from notifications once unlock is successful. + } else { + LOG(ERROR) << "Screen is not locked"; + NOTREACHED(); + } +} + +void LoginPerformer::ResolveInitialNetworkAuthFailure() { + DVLOG(1) << "auth_error: " << last_login_failure_.error().state(); + + switch (last_login_failure_.error().state()) { + case GoogleServiceAuthError::CONNECTION_FAILED: + case GoogleServiceAuthError::SERVICE_UNAVAILABLE: + case GoogleServiceAuthError::TWO_FACTOR: + case GoogleServiceAuthError::REQUEST_CANCELED: + // Offline auth already done. Online auth will be done next time + // or once user accesses web property. + VLOG(1) << "Granting user access based on offline auth only. " + << "Online login failed with " + << last_login_failure_.error().state(); + // Resolving initial online auth failure, no ScreenLock is active. + MessageLoop::current()->DeleteSoon(FROM_HERE, this); + return; + case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: + // Offline auth OK, so it might be the case of changed password. + password_changed_ = true; + case GoogleServiceAuthError::USER_NOT_SIGNED_UP: + case GoogleServiceAuthError::ACCOUNT_DELETED: + case GoogleServiceAuthError::ACCOUNT_DISABLED: + // Access not granted. User has to sign out. + // Request screen lock & show error message there. + case GoogleServiceAuthError::CAPTCHA_REQUIRED: + // User is requested to enter CAPTCHA challenge. + RequestScreenLock(); + return; + default: + // Unless there's new GoogleServiceAuthErrors state has been added. + NOTREACHED(); + return; + } +} + +void LoginPerformer::ResolveLockLoginFailure() { + if (last_login_failure_.reason() == LoginFailure::LOGIN_TIMED_OUT) { + LOG(WARNING) << "Online login timed out - unlocking screen. " + << "Granting user access based on offline auth only."; + RequestScreenUnlock(); + return; + } else if (last_login_failure_.reason() == + LoginFailure::NETWORK_AUTH_FAILED) { + ResolveLockNetworkAuthFailure(); + return; + } else if (last_login_failure_.reason() == + LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME || + last_login_failure_.reason() == + LoginFailure::DATA_REMOVAL_FAILED) { + LOG(ERROR) << "Cryptohome error, forcing sign out."; + } else { + // COULD_NOT_MOUNT_TMPFS, UNLOCK_FAILED should not happen here. + NOTREACHED(); + } + ScreenLocker::default_screen_locker()->Signout(); +} + +void LoginPerformer::ResolveLockNetworkAuthFailure() { + DCHECK(ScreenLocker::default_screen_locker()) + << "ScreenLocker instance doesn't exist."; + DCHECK(last_login_failure_.reason() == LoginFailure::NETWORK_AUTH_FAILED); + + std::wstring msg; + bool sign_out_only = false; + + DVLOG(1) << "auth_error: " << last_login_failure_.error().state(); + + switch (last_login_failure_.error().state()) { + case GoogleServiceAuthError::CONNECTION_FAILED: + case GoogleServiceAuthError::SERVICE_UNAVAILABLE: + case GoogleServiceAuthError::TWO_FACTOR: + case GoogleServiceAuthError::REQUEST_CANCELED: + // Offline auth already done. Online auth will be done next time + // or once user accesses web property. + LOG(WARNING) << "Granting user access based on offline auth only. " + << "Online login failed with " + << last_login_failure_.error().state(); + RequestScreenUnlock(); + return; + case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS: + // Password change detected. + msg = l10n_util::GetString(IDS_LOGIN_ERROR_PASSWORD_CHANGED); + break; + case GoogleServiceAuthError::USER_NOT_SIGNED_UP: + case GoogleServiceAuthError::ACCOUNT_DELETED: + case GoogleServiceAuthError::ACCOUNT_DISABLED: + // Access not granted. User has to sign out. + // Show error message using existing screen lock. + msg = l10n_util::GetString(IDS_LOGIN_ERROR_RESTRICTED); + sign_out_only = true; + break; + case GoogleServiceAuthError::CAPTCHA_REQUIRED: + // User is requested to enter CAPTCHA challenge. + msg = l10n_util::GetString(IDS_LOGIN_ERROR_AUTHENTICATING); + // TODO(nkostylev): Instruct ScreenLocker to show CAPTCHA input. + // http://crosbug.com/9812 + break; + default: + // Unless there's new GoogleServiceAuthError state has been added. + NOTREACHED(); + break; + } + + ScreenLocker::default_screen_locker()->ShowErrorMessage(msg, sign_out_only); +} + +void LoginPerformer::ResolveScreenLocked() { + DVLOG(1) << "Screen locked"; + ResolveLockNetworkAuthFailure(); +} + +void LoginPerformer::ResolveScreenUnlocked() { + DVLOG(1) << "Screen unlocked"; + registrar_.RemoveAll(); + // If screen was unlocked that was for a reason, should delete itself now. + MessageLoop::current()->DeleteSoon(FROM_HERE, this); +} + void LoginPerformer::StartAuthentication() { + DVLOG(1) << "Auth started"; BootTimesLoader::Get()->AddLoginTimeMarker("AuthStarted", false); - authenticator_ = LoginUtils::Get()->CreateAuthenticator(this); Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile(); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod(authenticator_.get(), - &Authenticator::AuthenticateToLogin, - profile, - username_, - password_, - captcha_token_, - captcha_)); + if (delegate_) { + authenticator_ = LoginUtils::Get()->CreateAuthenticator(this); + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(authenticator_.get(), + &Authenticator::AuthenticateToLogin, + profile, + username_, + password_, + captcha_token_, + captcha_)); + } else { + DCHECK(authenticator_.get()) + << "Authenticator instance doesn't exist for login attempt retry."; + // At this point offline auth has been successful, + // retry online auth, using existing Authenticator instance. + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(authenticator_.get(), + &Authenticator::RetryAuth, + profile, + username_, + password_, + captcha_token_, + captcha_)); + } password_.clear(); } diff --git a/chrome/browser/chromeos/login/login_performer.h b/chrome/browser/chromeos/login/login_performer.h index 7edf3cf..c67a173 100644 --- a/chrome/browser/chromeos/login/login_performer.h +++ b/chrome/browser/chromeos/login/login_performer.h @@ -15,22 +15,44 @@ #include "chrome/browser/chromeos/login/login_status_consumer.h" #include "chrome/browser/chromeos/login/signed_settings_helper.h" #include "chrome/common/net/gaia/google_service_auth_error.h" +#include "chrome/common/notification_observer.h" +#include "chrome/common/notification_registrar.h" namespace chromeos { // This class encapsulates sign in operations. -// Sign in is performed in a way that offline login is executed first. -// Once it's successful user homedir is mounted, UI is launched. -// If concurrent online login operation would fail that means: -// - User password has changed. Ask user for the new password. -// - User password has changed & CAPTCHA input is required. -// If |delegate_| is not NULL it will handle -// password changed and CAPTCHA dialogs. +// Sign in is performed in a way that offline auth is executed first. +// Once offline auth is OK - user homedir is mounted, UI is launched. +// At this point LoginPerformer |delegate_| is destroyed and it releases +// LP instance ownership. LP waits for online login result. +// If auth is succeeded, cookie fetcher is executed, LP instance deletes itself. +// +// If online login operation fails that means: +// (1) User password has changed. Ask user for the new password. +// (2) User password has changed and/or CAPTCHA input is required. +// (3) User account is deleted/disabled/not signed up. +// (4) Timeout/service unavailable/connection failed. +// +// Actions: +// (1)-(3): Request screen lock. +// (1) Ask for new user password. +// (2) Ask for new user password and/or CAPTCHA. +// (3) Display error message and allow "Sign Out" as the only action. +// (4) Delete LP instance since offline auth was OK. +// +// If |delegate_| is not NULL it will handle error messages, +// CAPTCHA dialog, password input. // If |delegate_| is NULL that does mean that LoginPerformer instance -// is waiting for online login operation. -// In case of failure use ScreenLock and ask for a new password. +// is waiting for successful online login or blocked on online login failure. +// In case of failure password/captcha +// input & error messages display is dedicated to ScreenLocker instance. +// +// 2 things make LoginPerfrormer instance exist longer: +// 1. ScreenLock active (pending correct new password input) +// 2. Pending online auth request. class LoginPerformer : public LoginStatusConsumer, - public SignedSettingsHelper::Callback { + public SignedSettingsHelper::Callback, + public NotificationObserver { public: // Delegate class to get notifications from the LoginPerformer. class Delegate : public LoginStatusConsumer { @@ -40,6 +62,14 @@ class LoginPerformer : public LoginStatusConsumer, }; explicit LoginPerformer(Delegate* delegate); + virtual ~LoginPerformer(); + + // Returns the default instance if it has been created. + // This instance is owned by delegate_ till it's destroyed. + // When LP instance lives by itself it's used by ScreenLocker instance. + static LoginPerformer* default_performer() { + return default_performer_; + } // LoginStatusConsumer implementation: virtual void OnLoginFailure(const LoginFailure& error); @@ -52,10 +82,15 @@ class LoginPerformer : public LoginStatusConsumer, virtual void OnPasswordChangeDetected( const GaiaAuthConsumer::ClientLoginResult& credentials); - // SignedSettingsHelper::Callback + // SignedSettingsHelper::Callback implementation: virtual void OnCheckWhiteListCompleted(bool success, const std::string& email); + // NotificationObserver implementation: + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); + // Performs login with the |username| and |password| specified. void Login(const std::string& username, const std::string& password); @@ -82,9 +117,33 @@ class LoginPerformer : public LoginStatusConsumer, void set_delegate(Delegate* delegate) { delegate_ = delegate; } private: + // Requests screen lock and subscribes to screen lock notifications. + void RequestScreenLock(); + + // Requests screen unlock. + void RequestScreenUnlock(); + + // Resolves initial LoginFailure::NETWORK_AUTH_FAILED error i.e. + // when screen is not locked yet. + void ResolveInitialNetworkAuthFailure(); + + // Resolves LoginFailure when screen is locked. + void ResolveLockLoginFailure(); + + // Resolves LoginFailure::NETWORK_AUTH_FAILED error when screen is locked. + // Uses ScreenLocker to show error message based on |last_login_failure_|. + void ResolveLockNetworkAuthFailure(); + + // Resolve ScreenLock changed state. + void ResolveScreenLocked(); + void ResolveScreenUnlocked(); + // Starts authentication. void StartAuthentication(); + // Default performer. Will be used by ScreenLocker. + static LoginPerformer* default_performer_; + // Used for logging in. scoped_refptr<Authenticator> authenticator_; @@ -108,6 +167,17 @@ class LoginPerformer : public LoginStatusConsumer, // Notifications receiver. Delegate* delegate_; + // True if password change has been detected. + // Once correct password is entered homedir migration is executed. + bool password_changed_; + + // Used for ScreenLock notifications. + NotificationRegistrar registrar_; + + // True if LoginPerformer has requested screen lock. Used to distinguish + // such requests with cases when screen is locked on its own. + bool screen_lock_requested_; + ScopedRunnableMethodFactory<LoginPerformer> method_factory_; DISALLOW_COPY_AND_ASSIGN(LoginPerformer); diff --git a/chrome/browser/chromeos/login/parallel_authenticator.cc b/chrome/browser/chromeos/login/parallel_authenticator.cc index ec499fb..27b7186 100644 --- a/chrome/browser/chromeos/login/parallel_authenticator.cc +++ b/chrome/browser/chromeos/login/parallel_authenticator.cc @@ -273,7 +273,9 @@ void ParallelAuthenticator::Resolve() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); bool request_pending = false; bool create = false; - switch (ResolveState()) { + ParallelAuthenticator::AuthState state = ResolveState(); + VLOG(1) << "Resolved state to: " << state; + switch (state) { case CONTINUE: case POSSIBLE_PW_CHANGE: case NO_MOUNT: diff --git a/chrome/browser/chromeos/login/password_changed_view.cc b/chrome/browser/chromeos/login/password_changed_view.cc index 22f953f..5a1d2d0 100644 --- a/chrome/browser/chromeos/login/password_changed_view.cc +++ b/chrome/browser/chromeos/login/password_changed_view.cc @@ -183,14 +183,4 @@ void PasswordChangedView::ButtonPressed(Button* sender, } } -bool PasswordChangedView::HandleKeystroke(views::Textfield* s, - const views::Textfield::Keystroke& keystroke) { - if (keystroke.GetKeyboardCode() == app::VKEY_RETURN) { - ExitDialog(); - return true; - } - - return false; -} - } // namespace chromeos diff --git a/chrome/browser/chromeos/login/password_changed_view.h b/chrome/browser/chromeos/login/password_changed_view.h index b7d45da..706e53b 100644 --- a/chrome/browser/chromeos/login/password_changed_view.h +++ b/chrome/browser/chromeos/login/password_changed_view.h @@ -63,7 +63,9 @@ class PasswordChangedView : public views::View, // views::Textfield::Controller overrides: virtual bool HandleKeystroke(views::Textfield* sender, - const views::Textfield::Keystroke& keystroke); + const views::Textfield::Keystroke& keystroke) { + return false; + } virtual void ContentsChanged(views::Textfield* sender, const string16& new_contents) {} diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc index 87a28dd..6a753a9 100644 --- a/chrome/browser/chromeos/login/screen_locker.cc +++ b/chrome/browser/chromeos/login/screen_locker.cc @@ -32,6 +32,7 @@ #include "chrome/browser/chromeos/language_preferences.h" #include "chrome/browser/chromeos/login/authenticator.h" #include "chrome/browser/chromeos/login/background_view.h" +#include "chrome/browser/chromeos/login/login_performer.h" #include "chrome/browser/chromeos/login/login_utils.h" #include "chrome/browser/chromeos/login/message_bubble.h" #include "chrome/browser/chromeos/login/screen_lock_view.h" @@ -725,14 +726,7 @@ void ScreenLocker::OnLoginFailure(const LoginFailure& error) { EnableInput(); // Don't enable signout button here as we're showing // MessageBubble. - gfx::Rect rect = screen_lock_view_->GetPasswordBoundsRelativeTo( - lock_widget_->GetRootView()); - gfx::Rect lock_widget_bounds; - lock_widget_->GetBounds(&lock_widget_bounds, false); - rect.Offset(lock_widget_bounds.x(), lock_widget_bounds.y()); - if (error_info_) - error_info_->Close(); std::wstring msg = l10n_util::GetString(IDS_LOGIN_ERROR_AUTHENTICATING); const std::string error_text = error.GetErrorString(); if (!error_text.empty()) @@ -743,21 +737,7 @@ void ScreenLocker::OnLoginFailure(const LoginFailure& error) { if (input_method_library->GetNumActiveInputMethods() > 1) msg += L"\n" + l10n_util::GetString(IDS_LOGIN_ERROR_KEYBOARD_SWITCH_HINT); - error_info_ = MessageBubble::ShowNoGrab( - lock_window_, - rect, - BubbleBorder::BOTTOM_LEFT, - ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING), - msg, - std::wstring(), // TODO: add help link - this); - if (mouse_event_relay_.get()) { - MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get()); - } - mouse_event_relay_.reset( - new MouseEventRelay(lock_widget_->GetNativeView()->window, - error_info_->GetNativeView()->window)); - MessageLoopForUI::current()->AddObserver(mouse_event_relay_.get()); + ShowErrorBubble(msg, BubbleBorder::BOTTOM_LEFT); } void ScreenLocker::OnLoginSuccess( @@ -801,12 +781,21 @@ void ScreenLocker::Authenticate(const string16& password) { authentication_start_time_ = base::Time::Now(); screen_lock_view_->SetEnabled(false); screen_lock_view_->SetSignoutEnabled(false); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - NewRunnableMethod(authenticator_.get(), - &Authenticator::AuthenticateToUnlock, - user_.email(), - UTF16ToUTF8(password))); + + // If LoginPerformer instance exists, + // initial online login phase is still active. + if (LoginPerformer::default_performer()) { + DVLOG(1) << "Delegating authentication to LoginPerformer."; + LoginPerformer::default_performer()->Login(user_.email(), + UTF16ToUTF8(password)); + } else { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + NewRunnableMethod(authenticator_.get(), + &Authenticator::AuthenticateToUnlock, + user_.email(), + UTF16ToUTF8(password))); + } } void ScreenLocker::ClearErrors() { @@ -835,6 +824,19 @@ void ScreenLocker::Signout() { } } +void ScreenLocker::ShowErrorMessage(const std::wstring& message, + bool sign_out_only) { + if (sign_out_only) { + screen_lock_view_->SetEnabled(false); + } else { + EnableInput(); + } + screen_lock_view_->SetSignoutEnabled(sign_out_only); + // Make sure that active Sign Out button is not hidden behind the bubble. + ShowErrorBubble(message, sign_out_only ? + BubbleBorder::BOTTOM_RIGHT : BubbleBorder::BOTTOM_LEFT); +} + void ScreenLocker::OnGrabInputs() { DVLOG(1) << "OnGrabInputs"; input_grabbed_ = true; @@ -980,6 +982,33 @@ void ScreenLocker::OnWindowManagerReady() { ScreenLockReady(); } +void ScreenLocker::ShowErrorBubble(const std::wstring& message, + BubbleBorder::ArrowLocation arrow_location) { + if (error_info_) + error_info_->Close(); + + gfx::Rect rect = screen_lock_view_->GetPasswordBoundsRelativeTo( + lock_widget_->GetRootView()); + gfx::Rect lock_widget_bounds; + lock_widget_->GetBounds(&lock_widget_bounds, false); + rect.Offset(lock_widget_bounds.x(), lock_widget_bounds.y()); + error_info_ = MessageBubble::ShowNoGrab( + lock_window_, + rect, + arrow_location, + ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_WARNING), + message, + std::wstring(), // TODO(nkostylev): Add help link. + this); + + if (mouse_event_relay_.get()) + MessageLoopForUI::current()->RemoveObserver(mouse_event_relay_.get()); + mouse_event_relay_.reset( + new MouseEventRelay(lock_widget_->GetNativeView()->window, + error_info_->GetNativeView()->window)); + MessageLoopForUI::current()->AddObserver(mouse_event_relay_.get()); +} + void ScreenLocker::StopScreenSaver() { if (background_view_->IsScreenSaverVisible()) { VLOG(1) << "StopScreenSaver"; diff --git a/chrome/browser/chromeos/login/screen_locker.h b/chrome/browser/chromeos/login/screen_locker.h index 853c40f..27e1404 100644 --- a/chrome/browser/chromeos/login/screen_locker.h +++ b/chrome/browser/chromeos/login/screen_locker.h @@ -47,6 +47,11 @@ class ScreenLocker : public LoginStatusConsumer, public: explicit ScreenLocker(const UserManager::User& user); + // Returns the default instance if it has been created. + static ScreenLocker* default_screen_locker() { + return screen_locker_; + } + // Initialize and show the screen locker. void Init(); @@ -76,6 +81,11 @@ class ScreenLocker : public LoginStatusConsumer, // Exit the chrome, which will sign out the current session. void Signout(); + // Disables all UI needed and shows error bubble with |message|. + // If |sign_out_only| is true then all other input except "Sign Out" + // button is blocked. + void ShowErrorMessage(const std::wstring& message, bool sign_out_only); + // Called when the all inputs are grabbed. void OnGrabInputs(); @@ -117,6 +127,11 @@ class ScreenLocker : public LoginStatusConsumer, // Called when the window manager is ready to handle locked state. void OnWindowManagerReady(); + // Shows error_info_ bubble with the |message| and |arrow_location| specified. + // Assumes that UI controls were locked before that. + void ShowErrorBubble(const std::wstring& message, + BubbleBorder::ArrowLocation arrow_location); + // Stops screen saver. void StopScreenSaver(); |