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