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