OLD | NEW |
---|---|
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 Loading... | |
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 |
OLD | NEW |