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

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

Powered by Google App Engine
This is Rietveld 408576698