Home | History | Annotate | Download | only in login
      1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/login/login_performer.h"
      6 
      7 #include <string>
      8 
      9 #include "base/logging.h"
     10 #include "base/message_loop.h"
     11 #include "base/metrics/histogram.h"
     12 #include "base/utf_string_conversions.h"
     13 #include "chrome/browser/browser_process.h"
     14 #include "chrome/browser/chromeos/boot_times_loader.h"
     15 #include "chrome/browser/chromeos/cros/cros_library.h"
     16 #include "chrome/browser/chromeos/cros/screen_lock_library.h"
     17 #include "chrome/browser/chromeos/cros_settings_names.h"
     18 #include "chrome/browser/chromeos/login/login_utils.h"
     19 #include "chrome/browser/chromeos/login/screen_locker.h"
     20 #include "chrome/browser/chromeos/user_cros_settings_provider.h"
     21 #include "chrome/browser/metrics/user_metrics.h"
     22 #include "chrome/browser/prefs/pref_service.h"
     23 #include "chrome/browser/profiles/profile.h"
     24 #include "chrome/browser/profiles/profile_manager.h"
     25 #include "chrome/common/pref_names.h"
     26 #include "content/browser/browser_thread.h"
     27 #include "content/common/notification_service.h"
     28 #include "content/common/notification_type.h"
     29 #include "grit/generated_resources.h"
     30 #include "ui/base/l10n/l10n_util.h"
     31 #include "ui/base/resource/resource_bundle.h"
     32 
     33 namespace chromeos {
     34 
     35 // Initialize default LoginPerformer.
     36 // static
     37 LoginPerformer* LoginPerformer::default_performer_ = NULL;
     38 
     39 LoginPerformer::LoginPerformer(Delegate* delegate)
     40     : last_login_failure_(LoginFailure::None()),
     41       delegate_(delegate),
     42       password_changed_(false),
     43       screen_lock_requested_(false),
     44       initial_online_auth_pending_(false),
     45       method_factory_(this) {
     46   DCHECK(default_performer_ == NULL)
     47       << "LoginPerformer should have only one instance.";
     48   default_performer_ = this;
     49 }
     50 
     51 LoginPerformer::~LoginPerformer() {
     52   DVLOG(1) << "Deleting LoginPerformer";
     53   DCHECK(default_performer_ != NULL) << "Default instance should exist.";
     54   default_performer_ = NULL;
     55 }
     56 
     57 ////////////////////////////////////////////////////////////////////////////////
     58 // LoginPerformer, LoginStatusConsumer implementation:
     59 
     60 void LoginPerformer::OnLoginFailure(const LoginFailure& failure) {
     61   UserMetrics::RecordAction(UserMetricsAction("Login_Failure"));
     62   UMA_HISTOGRAM_ENUMERATION("Login.FailureReason", failure.reason(),
     63                             LoginFailure::NUM_FAILURE_REASONS);
     64 
     65   DVLOG(1) << "failure.reason " << failure.reason();
     66   DVLOG(1) << "failure.error.state " << failure.error().state();
     67 
     68   last_login_failure_ = failure;
     69   if (delegate_) {
     70     captcha_.clear();
     71     captcha_token_.clear();
     72     if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED &&
     73         failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) {
     74       captcha_token_ = failure.error().captcha().token;
     75     }
     76     delegate_->OnLoginFailure(failure);
     77     return;
     78   }
     79 
     80   // Consequent online login failure with blocking UI on.
     81   // No difference between cases whether screen was locked by the user or
     82   // by LoginPerformer except for the very first screen lock while waiting
     83   // for online auth. Otherwise it will be SL active > timeout > screen unlock.
     84   // Display recoverable error message using ScreenLocker,
     85   // force sign out otherwise.
     86   if (ScreenLocker::default_screen_locker() && !initial_online_auth_pending_) {
     87     ResolveLockLoginFailure();
     88     return;
     89   }
     90   initial_online_auth_pending_ = false;
     91 
     92   // Offline auth - OK, online auth - failed.
     93   if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED) {
     94     ResolveInitialNetworkAuthFailure();
     95   } else if (failure.reason() == LoginFailure::LOGIN_TIMED_OUT) {
     96     VLOG(1) << "Online login timed out. "
     97             << "Granting user access based on offline auth only.";
     98     // ScreenLock is not active, it's ok to delete itself.
     99     MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    100   } else {
    101     // COULD_NOT_MOUNT_CRYPTOHOME, COULD_NOT_MOUNT_TMPFS:
    102     // happens during offline auth only.
    103     // UNLOCK_FAILED is used during normal screen lock case.
    104     // TODO(nkostylev) DATA_REMOVAL_FAILED - ?
    105     NOTREACHED();
    106   }
    107 }
    108 
    109 void LoginPerformer::OnLoginSuccess(
    110     const std::string& username,
    111     const std::string& password,
    112     const GaiaAuthConsumer::ClientLoginResult& credentials,
    113     bool pending_requests) {
    114   UserMetrics::RecordAction(UserMetricsAction("Login_Success"));
    115   // 0 - Login success offline and online. It's a new user. or it's an
    116   //     existing user and offline auth took longer than online auth.
    117   // 1 - Login success offline only. It's an existing user login.
    118   UMA_HISTOGRAM_ENUMERATION("Login.SuccessReason", pending_requests, 2);
    119 
    120   VLOG(1) << "LoginSuccess, pending_requests " << pending_requests;
    121   if (delegate_) {
    122     // After delegate_->OnLoginSuccess(...) is called, delegate_ releases
    123     // LoginPerformer ownership. LP now manages it's lifetime on its own.
    124     // 2 things could make it exist longer:
    125     // 1. ScreenLock active (pending correct new password input)
    126     // 2. Pending online auth request.
    127     if (!pending_requests)
    128       MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    129     else
    130       initial_online_auth_pending_ = true;
    131 
    132     delegate_->OnLoginSuccess(username,
    133                               password,
    134                               credentials,
    135                               pending_requests);
    136     return;
    137   } else {
    138     // Online login has succeeded.
    139     DCHECK(!pending_requests)
    140         << "Pending request w/o delegate_ should not happen!";
    141     // It is not guaranted, that profile creation has been finished yet. So use
    142     // async version here.
    143     credentials_ = credentials;
    144     ProfileManager::CreateDefaultProfileAsync(this);
    145   }
    146 }
    147 
    148 void LoginPerformer::OnProfileCreated(Profile* profile) {
    149   CHECK(profile);
    150 
    151   LoginUtils::Get()->FetchCookies(profile, credentials_);
    152   LoginUtils::Get()->FetchTokens(profile, credentials_);
    153   credentials_ = GaiaAuthConsumer::ClientLoginResult();
    154 
    155   // Don't unlock screen if it was locked while we're waiting
    156   // for initial online auth.
    157   if (ScreenLocker::default_screen_locker() &&
    158       !initial_online_auth_pending_) {
    159     DVLOG(1) << "Online login OK - unlocking screen.";
    160     RequestScreenUnlock();
    161     // Do not delete itself just yet, wait for unlock.
    162     // See ResolveScreenUnlocked().
    163     return;
    164   }
    165   initial_online_auth_pending_ = false;
    166   // There's nothing else that's holding LP from deleting itself -
    167   // no ScreenLock, no pending requests.
    168   MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    169 }
    170 
    171 void LoginPerformer::OnOffTheRecordLoginSuccess() {
    172   UserMetrics::RecordAction(
    173       UserMetricsAction("Login_GuestLoginSuccess"));
    174 
    175   if (delegate_)
    176     delegate_->OnOffTheRecordLoginSuccess();
    177   else
    178     NOTREACHED();
    179 }
    180 
    181 void LoginPerformer::OnPasswordChangeDetected(
    182     const GaiaAuthConsumer::ClientLoginResult& credentials) {
    183   cached_credentials_ = credentials;
    184   if (delegate_) {
    185     delegate_->OnPasswordChangeDetected(credentials);
    186   } else {
    187     last_login_failure_ =
    188         LoginFailure::FromNetworkAuthFailure(GoogleServiceAuthError(
    189             GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
    190     password_changed_ = true;
    191     DVLOG(1) << "Password change detected - locking screen.";
    192     RequestScreenLock();
    193   }
    194 }
    195 
    196 ////////////////////////////////////////////////////////////////////////////////
    197 // LoginPerformer, SignedSettingsHelper::Callback implementation:
    198 
    199 void LoginPerformer::OnCheckWhitelistCompleted(SignedSettings::ReturnCode code,
    200                                                const std::string& email) {
    201   if (code == SignedSettings::SUCCESS) {
    202     // Whitelist check passed, continue with authentication.
    203     StartAuthentication();
    204   } else {
    205     if (delegate_)
    206       delegate_->WhiteListCheckFailed(email);
    207     else
    208       NOTREACHED();
    209   }
    210 }
    211 
    212 ////////////////////////////////////////////////////////////////////////////////
    213 // LoginPerformer, NotificationObserver implementation:
    214 //
    215 
    216 void LoginPerformer::Observe(NotificationType type,
    217                              const NotificationSource& source,
    218                              const NotificationDetails& details) {
    219   if (type != NotificationType::SCREEN_LOCK_STATE_CHANGED)
    220     return;
    221 
    222   bool is_screen_locked = *Details<bool>(details).ptr();
    223   if (is_screen_locked) {
    224     if (screen_lock_requested_) {
    225       screen_lock_requested_ = false;
    226       ResolveScreenLocked();
    227     }
    228   } else {
    229     ResolveScreenUnlocked();
    230   }
    231 }
    232 
    233 ////////////////////////////////////////////////////////////////////////////////
    234 // LoginPerformer, public:
    235 
    236 void LoginPerformer::Login(const std::string& username,
    237                            const std::string& password) {
    238   username_ = username;
    239   password_ = password;
    240 
    241   // Whitelist check is always performed during initial login and
    242   // should not be performed when ScreenLock is active (pending online auth).
    243   if (!ScreenLocker::default_screen_locker()) {
    244     // Must not proceed without signature verification.
    245     UserCrosSettingsProvider user_settings;
    246     bool trusted_setting_available = user_settings.RequestTrustedAllowNewUser(
    247         method_factory_.NewRunnableMethod(&LoginPerformer::Login,
    248                                           username,
    249                                           password));
    250     if (!trusted_setting_available) {
    251       // Value of AllowNewUser setting is still not verified.
    252       // Another attempt will be invoked after verification completion.
    253       return;
    254     }
    255   }
    256 
    257   if (ScreenLocker::default_screen_locker() ||
    258       UserCrosSettingsProvider::cached_allow_new_user()) {
    259     // Starts authentication if guest login is allowed or online auth pending.
    260     StartAuthentication();
    261   } else {
    262     // Otherwise, do whitelist check first.
    263     PrefService* local_state = g_browser_process->local_state();
    264     CHECK(local_state);
    265     if (local_state->IsManagedPreference(kAccountsPrefUsers)) {
    266       if (UserCrosSettingsProvider::IsEmailInCachedWhitelist(username)) {
    267         StartAuthentication();
    268       } else {
    269         if (delegate_)
    270           delegate_->WhiteListCheckFailed(username);
    271         else
    272           NOTREACHED();
    273       }
    274     } else {
    275       // In case of signed settings: with current implementation we do not
    276       // trust whitelist returned by PrefService.  So make separate check.
    277       SignedSettingsHelper::Get()->StartCheckWhitelistOp(
    278           username, this);
    279     }
    280   }
    281 }
    282 
    283 void LoginPerformer::LoginOffTheRecord() {
    284   authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
    285   BrowserThread::PostTask(
    286       BrowserThread::UI, FROM_HERE,
    287       NewRunnableMethod(authenticator_.get(),
    288                         &Authenticator::LoginOffTheRecord));
    289 }
    290 
    291 void LoginPerformer::RecoverEncryptedData(const std::string& old_password) {
    292   BrowserThread::PostTask(
    293       BrowserThread::UI, FROM_HERE,
    294       NewRunnableMethod(authenticator_.get(),
    295                         &Authenticator::RecoverEncryptedData,
    296                         old_password,
    297                         cached_credentials_));
    298   cached_credentials_ = GaiaAuthConsumer::ClientLoginResult();
    299 }
    300 
    301 void LoginPerformer::ResyncEncryptedData() {
    302   BrowserThread::PostTask(
    303       BrowserThread::UI, FROM_HERE,
    304       NewRunnableMethod(authenticator_.get(),
    305                         &Authenticator::ResyncEncryptedData,
    306                         cached_credentials_));
    307   cached_credentials_ = GaiaAuthConsumer::ClientLoginResult();
    308 }
    309 
    310 ////////////////////////////////////////////////////////////////////////////////
    311 // LoginPerformer, private:
    312 
    313 void LoginPerformer::RequestScreenLock() {
    314   DVLOG(1) << "Screen lock requested";
    315   // Will receive notifications on screen unlock and delete itself.
    316   registrar_.Add(this,
    317                  NotificationType::SCREEN_LOCK_STATE_CHANGED,
    318                  NotificationService::AllSources());
    319   if (ScreenLocker::default_screen_locker()) {
    320     DVLOG(1) << "Screen already locked";
    321     ResolveScreenLocked();
    322   } else {
    323     screen_lock_requested_ = true;
    324     chromeos::CrosLibrary::Get()->GetScreenLockLibrary()->
    325         NotifyScreenLockRequested();
    326   }
    327 }
    328 
    329 void LoginPerformer::RequestScreenUnlock() {
    330   DVLOG(1) << "Screen unlock requested";
    331   if (ScreenLocker::default_screen_locker()) {
    332     chromeos::CrosLibrary::Get()->GetScreenLockLibrary()->
    333         NotifyScreenUnlockRequested();
    334     // Will unsubscribe from notifications once unlock is successful.
    335   } else {
    336     LOG(ERROR) << "Screen is not locked";
    337     NOTREACHED();
    338   }
    339 }
    340 
    341 void LoginPerformer::ResolveInitialNetworkAuthFailure() {
    342   DVLOG(1) << "auth_error: " << last_login_failure_.error().state();
    343 
    344   switch (last_login_failure_.error().state()) {
    345     case GoogleServiceAuthError::CONNECTION_FAILED:
    346     case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
    347     case GoogleServiceAuthError::TWO_FACTOR:
    348     case GoogleServiceAuthError::REQUEST_CANCELED:
    349       // Offline auth already done. Online auth will be done next time
    350       // or once user accesses web property.
    351       VLOG(1) << "Granting user access based on offline auth only. "
    352               << "Online login failed with "
    353               << last_login_failure_.error().state();
    354       // Resolving initial online auth failure, no ScreenLock is active.
    355       MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    356       return;
    357     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
    358       // Offline auth OK, so it might be the case of changed password.
    359       password_changed_ = true;
    360     case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
    361     case GoogleServiceAuthError::ACCOUNT_DELETED:
    362     case GoogleServiceAuthError::ACCOUNT_DISABLED:
    363       // Access not granted. User has to sign out.
    364       // Request screen lock & show error message there.
    365     case GoogleServiceAuthError::CAPTCHA_REQUIRED:
    366       // User is requested to enter CAPTCHA challenge.
    367       captcha_token_ = last_login_failure_.error().captcha().token;
    368       RequestScreenLock();
    369       return;
    370     default:
    371       // Unless there's new GoogleServiceAuthErrors state has been added.
    372       NOTREACHED();
    373       return;
    374   }
    375 }
    376 
    377 void LoginPerformer::ResolveLockLoginFailure() {
    378   if (last_login_failure_.reason() == LoginFailure::LOGIN_TIMED_OUT) {
    379      LOG(WARNING) << "Online login timed out - unlocking screen. "
    380                   << "Granting user access based on offline auth only.";
    381      RequestScreenUnlock();
    382      return;
    383    } else if (last_login_failure_.reason() ==
    384                   LoginFailure::NETWORK_AUTH_FAILED) {
    385      ResolveLockNetworkAuthFailure();
    386      return;
    387    } else if (last_login_failure_.reason() ==
    388                   LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME ||
    389               last_login_failure_.reason() ==
    390                   LoginFailure::DATA_REMOVAL_FAILED) {
    391      LOG(ERROR) << "Cryptohome error, forcing sign out.";
    392    } else {
    393      // COULD_NOT_MOUNT_TMPFS, UNLOCK_FAILED should not happen here.
    394      NOTREACHED();
    395    }
    396    ScreenLocker::default_screen_locker()->Signout();
    397 }
    398 
    399 void LoginPerformer::ResolveLockNetworkAuthFailure() {
    400   DCHECK(ScreenLocker::default_screen_locker())
    401       << "ScreenLocker instance doesn't exist.";
    402   DCHECK(last_login_failure_.reason() == LoginFailure::NETWORK_AUTH_FAILED);
    403 
    404   string16 msg;
    405   bool sign_out_only = false;
    406 
    407   DVLOG(1) << "auth_error: " << last_login_failure_.error().state();
    408 
    409   switch (last_login_failure_.error().state()) {
    410     case GoogleServiceAuthError::CONNECTION_FAILED:
    411     case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
    412     case GoogleServiceAuthError::TWO_FACTOR:
    413     case GoogleServiceAuthError::REQUEST_CANCELED:
    414       // Offline auth already done. Online auth will be done next time
    415       // or once user accesses web property.
    416       LOG(WARNING) << "Granting user access based on offline auth only. "
    417                    << "Online login failed with "
    418                    << last_login_failure_.error().state();
    419       RequestScreenUnlock();
    420       return;
    421     case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
    422       // Password change detected.
    423       msg = l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_PASSWORD_CHANGED);
    424       break;
    425     case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
    426     case GoogleServiceAuthError::ACCOUNT_DELETED:
    427     case GoogleServiceAuthError::ACCOUNT_DISABLED:
    428       // Access not granted. User has to sign out.
    429       // Show error message using existing screen lock.
    430       msg = l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_RESTRICTED);
    431       sign_out_only = true;
    432       break;
    433     case GoogleServiceAuthError::CAPTCHA_REQUIRED:
    434       // User is requested to enter CAPTCHA challenge.
    435       captcha_token_ = last_login_failure_.error().captcha().token;
    436       msg = l10n_util::GetStringUTF16(IDS_LOGIN_ERROR_PASSWORD_CHANGED);
    437       ScreenLocker::default_screen_locker()->ShowCaptchaAndErrorMessage(
    438           last_login_failure_.error().captcha().image_url,
    439           UTF16ToWide(msg));
    440       return;
    441     default:
    442       // Unless there's new GoogleServiceAuthError state has been added.
    443       NOTREACHED();
    444       break;
    445   }
    446 
    447   ScreenLocker::default_screen_locker()->ShowErrorMessage(UTF16ToWide(msg),
    448                                                           sign_out_only);
    449 }
    450 
    451 void LoginPerformer::ResolveScreenLocked() {
    452   DVLOG(1) << "Screen locked";
    453   ResolveLockNetworkAuthFailure();
    454 }
    455 
    456 void LoginPerformer::ResolveScreenUnlocked() {
    457   DVLOG(1) << "Screen unlocked";
    458   registrar_.RemoveAll();
    459   // If screen was unlocked that was for a reason, should delete itself now.
    460   MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    461 }
    462 
    463 void LoginPerformer::StartAuthentication() {
    464   DVLOG(1) << "Auth started";
    465   BootTimesLoader::Get()->AddLoginTimeMarker("AuthStarted", false);
    466   Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile();
    467   if (delegate_) {
    468     authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
    469     BrowserThread::PostTask(
    470         BrowserThread::UI, FROM_HERE,
    471         NewRunnableMethod(authenticator_.get(),
    472                           &Authenticator::AuthenticateToLogin,
    473                           profile,
    474                           username_,
    475                           password_,
    476                           captcha_token_,
    477                           captcha_));
    478   } else {
    479     DCHECK(authenticator_.get())
    480         << "Authenticator instance doesn't exist for login attempt retry.";
    481     // At this point offline auth has been successful,
    482     // retry online auth, using existing Authenticator instance.
    483     BrowserThread::PostTask(
    484         BrowserThread::UI, FROM_HERE,
    485         NewRunnableMethod(authenticator_.get(),
    486                           &Authenticator::RetryAuth,
    487                           profile,
    488                           username_,
    489                           password_,
    490                           captcha_token_,
    491                           captcha_));
    492   }
    493   password_.clear();
    494 }
    495 
    496 }  // namespace chromeos
    497