Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1415)

Side by Side Diff: chrome/browser/chromeos/login/login_performer.cc

Issue 3583013: [cros] Add blocking UI on offline: OK, online auth: fail case. (Closed) Base URL: http://src.chromium.org/git/chromium.git
Patch Set: removed unused flag Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/login/login_performer.h" 5 #include "chrome/browser/chromeos/login/login_performer.h"
6 6
7 #include <string>
8
9 #include "app/l10n_util.h"
10 #include "app/resource_bundle.h"
7 #include "base/logging.h" 11 #include "base/logging.h"
8 #include "base/message_loop.h" 12 #include "base/message_loop.h"
9 #include "chrome/browser/browser_process.h" 13 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/browser_thread.h" 14 #include "chrome/browser/browser_thread.h"
11 #include "chrome/browser/chromeos/boot_times_loader.h" 15 #include "chrome/browser/chromeos/boot_times_loader.h"
16 #include "chrome/browser/chromeos/cros/cros_library.h"
17 #include "chrome/browser/chromeos/cros/screen_lock_library.h"
12 #include "chrome/browser/chromeos/login/login_utils.h" 18 #include "chrome/browser/chromeos/login/login_utils.h"
19 #include "chrome/browser/chromeos/login/screen_locker.h"
13 #include "chrome/browser/chromeos/user_cros_settings_provider.h" 20 #include "chrome/browser/chromeos/user_cros_settings_provider.h"
21 #include "chrome/common/notification_service.h"
22 #include "chrome/common/notification_type.h"
14 #include "chrome/browser/profile.h" 23 #include "chrome/browser/profile.h"
15 #include "chrome/browser/profile_manager.h" 24 #include "chrome/browser/profile_manager.h"
25 #include "grit/generated_resources.h"
16 26
17 namespace chromeos { 27 namespace chromeos {
18 28
19 namespace { 29 // Initialize default LoginPerformer.
20 } // namespace 30 // static
31 LoginPerformer* LoginPerformer::default_performer_ = NULL;
21 32
22 LoginPerformer::LoginPerformer(Delegate* delegate) 33 LoginPerformer::LoginPerformer(Delegate* delegate)
23 : last_login_failure_(LoginFailure::None()), 34 : last_login_failure_(LoginFailure::None()),
24 delegate_(delegate) {} 35 delegate_(delegate),
36 password_changed_(false),
37 screen_lock_requested_(false) {
38 DCHECK(default_performer_ == NULL)
39 << "LoginPerformer should have only one instance.";
40 default_performer_ = this;
41 }
42
43 LoginPerformer::~LoginPerformer() {
44 DVLOG(1) << "Deleting LoginPerformer";
45 DCHECK(default_performer_ != NULL) << "Default instance should exist.";
46 default_performer_ = NULL;
47 }
25 48
26 //////////////////////////////////////////////////////////////////////////////// 49 ////////////////////////////////////////////////////////////////////////////////
27 // LoginPerformer, LoginStatusConsumer implementation: 50 // LoginPerformer, LoginStatusConsumer implementation:
28 51
29 void LoginPerformer::OnLoginFailure(const LoginFailure& failure) { 52 void LoginPerformer::OnLoginFailure(const LoginFailure& failure) {
30 last_login_failure_ = failure; 53 DVLOG(1) << "failure.reason " << failure.reason();
31 if (delegate_) { 54 DVLOG(1) << "failure.error.state " << failure.error().state();
32 captcha_.clear(); 55
33 captcha_token_.clear(); 56 last_login_failure_ = failure;
34 if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED && 57 if (delegate_) {
35 failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) { 58 captcha_.clear();
36 captcha_token_ = failure.error().captcha().token; 59 captcha_token_.clear();
37 } 60 if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED &&
38 delegate_->OnLoginFailure(failure); 61 failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) {
39 } else { 62 captcha_token_ = failure.error().captcha().token;
40 // TODO(nkostylev): Provide blocking UI using ScreenLocker. 63 }
41 } 64 delegate_->OnLoginFailure(failure);
65 return;
66 }
67
68 // Consequent online login failure with blocking UI on.
69 // No difference between cases whether screen was locked by the user or
70 // by LoginPerformer.
71 // Display recoverable error message using ScreenLocker,
72 // force sign out otherwise.
73 if (ScreenLocker::default_screen_locker()) {
74 ResolveLockLoginFailure();
75 return;
76 }
77
78 // Offline auth - OK, online auth - failed.
79 if (failure.reason() == LoginFailure::NETWORK_AUTH_FAILED) {
80 ResolveInitialNetworkAuthFailure();
81 } else if (failure.reason() == LoginFailure::LOGIN_TIMED_OUT) {
82 LOG(INFO) << "Online login timed out. "
Chris Masone 2010/12/01 18:12:21 VLOG(1)?
Nikita (slow) 2010/12/02 10:39:52 Done.
83 << "Granting user access based on offline auth only.";
84 // ScreenLock is not active, it's ok to delete itself.
85 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
86 } else {
87 // COULD_NOT_MOUNT_CRYPTOHOME, COULD_NOT_MOUNT_TMPFS:
88 // happens during offline auth only.
89 // UNLOCK_FAILED is used during normal screen lock case.
90 // TODO(nkostylev) DATA_REMOVAL_FAILED - ?
91 NOTREACHED();
92 }
42 } 93 }
43 94
44 void LoginPerformer::OnLoginSuccess( 95 void LoginPerformer::OnLoginSuccess(
45 const std::string& username, 96 const std::string& username,
46 const std::string& password, 97 const std::string& password,
47 const GaiaAuthConsumer::ClientLoginResult& credentials, 98 const GaiaAuthConsumer::ClientLoginResult& credentials,
48 bool pending_requests) { 99 bool pending_requests) {
100 VLOG(1) << "LoginSuccess, pending_requests " << pending_requests;
49 if (delegate_) { 101 if (delegate_) {
50 delegate_->OnLoginSuccess(username, 102 delegate_->OnLoginSuccess(username,
51 password, 103 password,
52 credentials, 104 credentials,
53 pending_requests); 105 pending_requests);
106 // After delegate_->OnLoginSuccess(...) is called, delegate_ releases
107 // LoginPerformer ownership. LP now manages it's lifetime on its own.
108 // 2 things could make it exist longer:
109 // 1. ScreenLock active (pending correct new password input)
110 // 2. Pending online auth request.
54 if (!pending_requests) 111 if (!pending_requests)
55 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 112 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
56 } else { 113 } else {
57 DCHECK(!pending_requests); 114 DCHECK(!pending_requests)
58 // Online login has succeeded. Delete our instance. 115 << "Pending request w/o delegate_ should not happen!";
116 // Online login has succeeded.
117 // TODO(nkostylev): Execute CookieFetcher->AttemptFetch() here once
Nikita (slow) 2010/12/01 15:02:52 http://crosbug.com/9814
oshima 2010/12/01 23:46:53 Add the above link in the comment.
Nikita (slow) 2010/12/02 10:39:52 Done.
118 // async login is implemented.
119 if (ScreenLocker::default_screen_locker()) {
120 DVLOG(1) << "Online login OK - unlocking screen.";
121 RequestScreenUnlock();
122 // Do not delete itself just yet, wait for unlock.
123 // See ResolveScreenUnlocked().
124 return;
125 }
126 // There's nothing else that's holding LP from deleting itself -
127 // no ScreenLock, no pending requests.
59 MessageLoop::current()->DeleteSoon(FROM_HERE, this); 128 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
60 } 129 }
61 } 130 }
62 131
63 void LoginPerformer::OnOffTheRecordLoginSuccess() { 132 void LoginPerformer::OnOffTheRecordLoginSuccess() {
64 if (delegate_) 133 if (delegate_)
65 delegate_->OnOffTheRecordLoginSuccess(); 134 delegate_->OnOffTheRecordLoginSuccess();
66 else 135 else
67 NOTREACHED(); 136 NOTREACHED();
68 } 137 }
69 138
70 void LoginPerformer::OnPasswordChangeDetected( 139 void LoginPerformer::OnPasswordChangeDetected(
71 const GaiaAuthConsumer::ClientLoginResult& credentials) { 140 const GaiaAuthConsumer::ClientLoginResult& credentials) {
72 cached_credentials_ = credentials; 141 cached_credentials_ = credentials;
73 if (delegate_) { 142 if (delegate_) {
74 delegate_->OnPasswordChangeDetected(credentials); 143 delegate_->OnPasswordChangeDetected(credentials);
75 } else { 144 } else {
76 // TODO(nkostylev): Provide blocking UI using ScreenLocker. 145 last_login_failure_ =
146 LoginFailure::FromNetworkAuthFailure(GoogleServiceAuthError(
147 GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
148 password_changed_ = true;
149 DVLOG(1) << "Password change detected - locking screen.";
150 RequestScreenLock();
77 } 151 }
78 } 152 }
79 153
80 //////////////////////////////////////////////////////////////////////////////// 154 ////////////////////////////////////////////////////////////////////////////////
81 // LoginPerformer, SignedSettingsHelper::Callback implementation: 155 // LoginPerformer, SignedSettingsHelper::Callback implementation:
82 156
83 void LoginPerformer::OnCheckWhiteListCompleted(bool success, 157 void LoginPerformer::OnCheckWhiteListCompleted(bool success,
84 const std::string& email) { 158 const std::string& email) {
85 if (success) { 159 if (success) {
86 // Whitelist check passed, continue with authentication. 160 // Whitelist check passed, continue with authentication.
87 StartAuthentication(); 161 StartAuthentication();
88 } else { 162 } else {
89 if (delegate_) 163 if (delegate_)
90 delegate_->WhiteListCheckFailed(email); 164 delegate_->WhiteListCheckFailed(email);
91 else 165 else
92 NOTREACHED(); 166 NOTREACHED();
93 } 167 }
94 } 168 }
95 169
96 //////////////////////////////////////////////////////////////////////////////// 170 ////////////////////////////////////////////////////////////////////////////////
171 // LoginPerformer, NotificationObserver implementation:
172 //
173
174 void LoginPerformer::Observe(NotificationType type,
175 const NotificationSource& source,
176 const NotificationDetails& details) {
177 if (type != NotificationType::SCREEN_LOCK_STATE_CHANGED)
178 return;
179
180 bool is_screen_locked = *Details<bool>(details).ptr();
181 if (is_screen_locked) {
182 if (screen_lock_requested_) {
183 screen_lock_requested_ = false;
184 ResolveScreenLocked();
185 }
186 } else {
187 ResolveScreenUnlocked();
188 }
189 }
190
191 ////////////////////////////////////////////////////////////////////////////////
97 // LoginPerformer, public: 192 // LoginPerformer, public:
98 193
99 void LoginPerformer::Login(const std::string& username, 194 void LoginPerformer::Login(const std::string& username,
100 const std::string& password) { 195 const std::string& password) {
101 username_ = username; 196 username_ = username;
102 password_ = password; 197 password_ = password;
103 if (UserCrosSettingsProvider::cached_allow_new_user()) { 198 // Whitelist check is performed during offline login only.
Chris Masone 2010/12/01 18:12:21 During offline login only? It shouldn't happen du
Nikita (slow) 2010/12/02 10:39:52 Yes, comment was wrong, fixed.
199 if (ScreenLocker::default_screen_locker() ||
200 UserCrosSettingsProvider::cached_allow_new_user()) {
104 // Starts authentication if guest login is allowed. 201 // Starts authentication if guest login is allowed.
105 StartAuthentication(); 202 StartAuthentication();
106 } else { 203 } else {
107 // Otherwise, do whitelist check first. 204 // Otherwise, do whitelist check first.
108 SignedSettingsHelper::Get()->StartCheckWhitelistOp( 205 SignedSettingsHelper::Get()->StartCheckWhitelistOp(
109 username, this); 206 username, this);
110 } 207 }
111 } 208 }
112 209
113 void LoginPerformer::LoginOffTheRecord() { 210 void LoginPerformer::LoginOffTheRecord() {
(...skipping 19 matching lines...) Expand all
133 BrowserThread::UI, FROM_HERE, 230 BrowserThread::UI, FROM_HERE,
134 NewRunnableMethod(authenticator_.get(), 231 NewRunnableMethod(authenticator_.get(),
135 &Authenticator::ResyncEncryptedData, 232 &Authenticator::ResyncEncryptedData,
136 cached_credentials_)); 233 cached_credentials_));
137 cached_credentials_ = GaiaAuthConsumer::ClientLoginResult(); 234 cached_credentials_ = GaiaAuthConsumer::ClientLoginResult();
138 } 235 }
139 236
140 //////////////////////////////////////////////////////////////////////////////// 237 ////////////////////////////////////////////////////////////////////////////////
141 // LoginPerformer, private: 238 // LoginPerformer, private:
142 239
240 void LoginPerformer::RequestScreenLock() {
241 DVLOG(1) << "Screen lock requested";
242 if (ScreenLocker::default_screen_locker()) {
243 DVLOG(1) << "Screen already locked";
244 ResolveScreenLocked();
245 } else {
246 screen_lock_requested_ = true;
247 registrar_.Add(
248 this,
249 NotificationType::SCREEN_LOCK_STATE_CHANGED,
250 NotificationService::AllSources());
251 chromeos::CrosLibrary::Get()->GetScreenLockLibrary()->
252 NotifyScreenLockRequested();
253 }
254 }
255
256 void LoginPerformer::RequestScreenUnlock() {
257 DVLOG(1) << "Screen unlock requested";
258 if (ScreenLocker::default_screen_locker()) {
259 chromeos::CrosLibrary::Get()->GetScreenLockLibrary()->
260 NotifyScreenUnlockRequested();
261 // Will unsubscribe from notifications once unlock is successful.
262 } else {
263 LOG(ERROR) << "Screen is not locked";
264 NOTREACHED();
265 }
266 }
267
268 void LoginPerformer::ResolveInitialNetworkAuthFailure() {
269 DVLOG(1) << "auth_error: " << last_login_failure_.error().state();
270
271 switch (last_login_failure_.error().state()) {
272 case GoogleServiceAuthError::CONNECTION_FAILED:
273 case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
274 case GoogleServiceAuthError::TWO_FACTOR:
275 case GoogleServiceAuthError::REQUEST_CANCELED:
276 // Offline auth already done. Online auth will be done next time
277 // or once user accesses web property.
278 LOG(INFO) << "Granting user access based on offline auth only. "
279 << "Online login failed with "
280 << last_login_failure_.error().state();
281 // Resolving initial online auth failure, no ScreenLock is active.
282 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
283 return;
284 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
285 // Offline auth OK, so it might be the case of changed password.
286 password_changed_ = true;
287 case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
288 case GoogleServiceAuthError::ACCOUNT_DELETED:
289 case GoogleServiceAuthError::ACCOUNT_DISABLED:
290 // Access not granted. User has to sign out.
291 // Request screen lock & show error message there.
292 case GoogleServiceAuthError::CAPTCHA_REQUIRED:
293 // User is requested to enter CAPTCHA challenge.
294 RequestScreenLock();
295 return;
296 default:
297 // Unless there's new GoogleServiceAuthErrors state has been added.
298 NOTREACHED();
299 return;
300 }
301 }
302
303 void LoginPerformer::ResolveLockLoginFailure() {
304 if (last_login_failure_.reason() == LoginFailure::LOGIN_TIMED_OUT) {
305 LOG(INFO) << "Online login timed out - unlocking screen. "
Chris Masone 2010/12/01 18:12:21 Maybe LOG(WARNING)?
Nikita (slow) 2010/12/02 10:39:52 Done.
306 << "Granting user access based on offline auth only.";
307 RequestScreenUnlock();
308 return;
309 } else if (last_login_failure_.reason() ==
310 LoginFailure::NETWORK_AUTH_FAILED) {
311 ResolveLockNetworkAuthFailure();
312 return;
313 } else if (last_login_failure_.reason() ==
314 LoginFailure::COULD_NOT_MOUNT_CRYPTOHOME ||
315 last_login_failure_.reason() ==
316 LoginFailure::DATA_REMOVAL_FAILED) {
317 LOG(ERROR) << "Cryptohome error, forcing sign out.";
318 } else {
319 // COULD_NOT_MOUNT_TMPFS, UNLOCK_FAILED should not happen here.
320 NOTREACHED();
321 }
322 ScreenLocker::default_screen_locker()->Signout();
323 }
324
325 void LoginPerformer::ResolveLockNetworkAuthFailure() {
326 DCHECK(ScreenLocker::default_screen_locker())
327 << "ScreenLocker instance doesn't exist.";
328 DCHECK(last_login_failure_.reason() == LoginFailure::NETWORK_AUTH_FAILED);
329
330 std::wstring msg;
331 bool sign_out_only = false;
332
333 DVLOG(1) << "auth_error: " << last_login_failure_.error().state();
334
335 switch (last_login_failure_.error().state()) {
336 case GoogleServiceAuthError::CONNECTION_FAILED:
337 case GoogleServiceAuthError::SERVICE_UNAVAILABLE:
338 case GoogleServiceAuthError::TWO_FACTOR:
339 case GoogleServiceAuthError::REQUEST_CANCELED:
340 // Offline auth already done. Online auth will be done next time
341 // or once user accesses web property.
342 LOG(INFO) << "Granting user access based on offline auth only. "
343 << "Online login failed with "
344 << last_login_failure_.error().state();
345 RequestScreenUnlock();
346 return;
347 case GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS:
348 // Password change detected.
349 msg = l10n_util::GetString(IDS_LOGIN_ERROR_PASSWORD_CHANGED);
350 break;
351 case GoogleServiceAuthError::USER_NOT_SIGNED_UP:
352 case GoogleServiceAuthError::ACCOUNT_DELETED:
353 case GoogleServiceAuthError::ACCOUNT_DISABLED:
354 // Access not granted. User has to sign out.
355 // Show error message using existing screen lock.
356 msg = l10n_util::GetString(IDS_LOGIN_ERROR_RESTRICTED);
357 sign_out_only = true;
358 break;
359 case GoogleServiceAuthError::CAPTCHA_REQUIRED:
360 // User is requested to enter CAPTCHA challenge.
361 msg = l10n_util::GetString(IDS_LOGIN_ERROR_AUTHENTICATING);
362 // TODO(nkostylev): Instruct ScreenLocker to show CAPTCHA input.
Nikita (slow) 2010/12/01 15:02:52 http://crosbug.com/9812
oshima 2010/12/01 23:46:53 include bug in the comment.
Nikita (slow) 2010/12/02 10:39:52 Done.
363 break;
364 default:
365 // Unless there's new GoogleServiceAuthError state has been added.
366 NOTREACHED();
367 break;
368 }
369
370 ScreenLocker::default_screen_locker()->ShowErrorMessage(msg, sign_out_only);
371 }
372
373 void LoginPerformer::ResolveScreenLocked() {
374 DVLOG(1) << "Screen locked";
375 ResolveLockNetworkAuthFailure();
376 }
377
378 void LoginPerformer::ResolveScreenUnlocked() {
379 DVLOG(1) << "Screen unlocked";
380 registrar_.RemoveAll();
381 // If screen was unlocked that was for a reason, should delete itself now.
382 MessageLoop::current()->DeleteSoon(FROM_HERE, this);
383 }
384
143 void LoginPerformer::StartAuthentication() { 385 void LoginPerformer::StartAuthentication() {
386 DVLOG(1) << "Auth started";
144 BootTimesLoader::Get()->AddLoginTimeMarker("AuthStarted", false); 387 BootTimesLoader::Get()->AddLoginTimeMarker("AuthStarted", false);
145 authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
146 Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile(); 388 Profile* profile = g_browser_process->profile_manager()->GetDefaultProfile();
147 BrowserThread::PostTask( 389 if (delegate_) {
148 BrowserThread::UI, FROM_HERE, 390 authenticator_ = LoginUtils::Get()->CreateAuthenticator(this);
149 NewRunnableMethod(authenticator_.get(), 391 BrowserThread::PostTask(
150 &Authenticator::AuthenticateToLogin, 392 BrowserThread::UI, FROM_HERE,
151 profile, 393 NewRunnableMethod(authenticator_.get(),
152 username_, 394 &Authenticator::AuthenticateToLogin,
153 password_, 395 profile,
154 captcha_token_, 396 username_,
155 captcha_)); 397 password_,
398 captcha_token_,
399 captcha_));
400 } else {
401 DCHECK(authenticator_.get())
402 << "Authenticator instance doesn't exist for login attempt retry.";
403 // At this point offline auth has been successful,
404 // retry online auth, using existing Authenticator instance.
405 BrowserThread::PostTask(
406 BrowserThread::UI, FROM_HERE,
407 NewRunnableMethod(authenticator_.get(),
408 &Authenticator::RetryAuth,
409 profile,
410 username_,
411 password_,
412 captcha_token_,
413 captcha_));
414 }
156 password_.clear(); 415 password_.clear();
157 } 416 }
158 417
159 } // namespace chromeos 418 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698