• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
LoginPerformer(Delegate * delegate)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 
~LoginPerformer()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 
OnLoginFailure(const LoginFailure & failure)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 
OnLoginSuccess(const std::string & username,const std::string & password,const GaiaAuthConsumer::ClientLoginResult & credentials,bool pending_requests)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 
OnProfileCreated(Profile * profile)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 
OnOffTheRecordLoginSuccess()171 void LoginPerformer::OnOffTheRecordLoginSuccess() {
172   UserMetrics::RecordAction(
173       UserMetricsAction("Login_GuestLoginSuccess"));
174 
175   if (delegate_)
176     delegate_->OnOffTheRecordLoginSuccess();
177   else
178     NOTREACHED();
179 }
180 
OnPasswordChangeDetected(const GaiaAuthConsumer::ClientLoginResult & credentials)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 
OnCheckWhitelistCompleted(SignedSettings::ReturnCode code,const std::string & email)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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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 
Login(const std::string & username,const std::string & password)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 
LoginOffTheRecord()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 
RecoverEncryptedData(const std::string & old_password)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 
ResyncEncryptedData()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 
RequestScreenLock()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 
RequestScreenUnlock()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 
ResolveInitialNetworkAuthFailure()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 
ResolveLockLoginFailure()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 
ResolveLockNetworkAuthFailure()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 
ResolveScreenLocked()451 void LoginPerformer::ResolveScreenLocked() {
452   DVLOG(1) << "Screen locked";
453   ResolveLockNetworkAuthFailure();
454 }
455 
ResolveScreenUnlocked()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 
StartAuthentication()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