1 // Copyright (c) 2012 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/online_attempt.h" 6 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/logging.h" 11 #include "base/memory/ref_counted.h" 12 #include "base/memory/scoped_ptr.h" 13 #include "chrome/browser/chromeos/login/auth_attempt_state.h" 14 #include "chrome/browser/chromeos/login/auth_attempt_state_resolver.h" 15 #include "chrome/browser/chromeos/login/user.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/profiles/profile_manager.h" 18 #include "content/public/browser/browser_thread.h" 19 #include "google_apis/gaia/gaia_auth_consumer.h" 20 #include "google_apis/gaia/gaia_auth_fetcher.h" 21 #include "google_apis/gaia/gaia_constants.h" 22 #include "net/base/load_flags.h" 23 #include "net/base/net_errors.h" 24 #include "net/url_request/url_request_status.h" 25 #include "third_party/libjingle/source/talk/base/urlencode.h" 26 27 using content::BrowserThread; 28 29 namespace chromeos { 30 31 // static 32 const int OnlineAttempt::kClientLoginTimeoutMs = 10000; 33 34 OnlineAttempt::OnlineAttempt(AuthAttemptState* current_attempt, 35 AuthAttemptStateResolver* callback) 36 : attempt_(current_attempt), 37 resolver_(callback), 38 weak_factory_(this), 39 try_again_(true) { 40 DCHECK(attempt_->user_type == User::USER_TYPE_REGULAR); 41 } 42 43 OnlineAttempt::~OnlineAttempt() { 44 // Just to be sure. 45 if (client_fetcher_.get()) 46 client_fetcher_->CancelRequest(); 47 } 48 49 void OnlineAttempt::Initiate(Profile* auth_profile) { 50 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 51 client_fetcher_.reset( 52 new GaiaAuthFetcher(this, GaiaConstants::kChromeOSSource, 53 auth_profile->GetRequestContext())); 54 BrowserThread::PostTask( 55 BrowserThread::UI, FROM_HERE, 56 base::Bind(&OnlineAttempt::TryClientLogin, weak_factory_.GetWeakPtr())); 57 } 58 59 void OnlineAttempt::OnClientLoginSuccess( 60 const GaiaAuthConsumer::ClientLoginResult& unused) { 61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 62 VLOG(1) << "Online login successful!"; 63 64 weak_factory_.InvalidateWeakPtrs(); 65 66 if (attempt_->hosted_policy() == GaiaAuthFetcher::HostedAccountsAllowed && 67 attempt_->is_first_time_user()) { 68 // First time user, and we don't know if the account is HOSTED or not. 69 // Since we don't allow HOSTED accounts to log in, we need to try 70 // again, without allowing HOSTED accounts. 71 // 72 // NOTE: we used to do this in the opposite order, so that we'd only 73 // try the HOSTED pathway if GOOGLE-only failed. This breaks CAPTCHA 74 // handling, though. 75 attempt_->DisableHosted(); 76 TryClientLogin(); 77 return; 78 } 79 TriggerResolve(LoginFailure::LoginFailureNone()); 80 } 81 82 void OnlineAttempt::OnClientLoginFailure( 83 const GoogleServiceAuthError& error) { 84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 85 86 weak_factory_.InvalidateWeakPtrs(); 87 88 if (error.state() == GoogleServiceAuthError::REQUEST_CANCELED) { 89 if (try_again_) { 90 try_again_ = false; 91 // TODO(cmasone): add UMA tracking for this to see if we can remove it. 92 LOG(ERROR) << "Login attempt canceled!?!? Trying again."; 93 TryClientLogin(); 94 return; 95 } 96 LOG(ERROR) << "Login attempt canceled again? Already retried..."; 97 } 98 99 if (error.state() == GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS && 100 attempt_->is_first_time_user() && 101 attempt_->hosted_policy() != GaiaAuthFetcher::HostedAccountsAllowed) { 102 // This was a first-time login, we already tried allowing HOSTED accounts 103 // and succeeded. That we've failed with INVALID_GAIA_CREDENTIALS now 104 // indicates that the account is HOSTED. 105 LOG(WARNING) << "Rejecting valid HOSTED account."; 106 TriggerResolve(LoginFailure::FromNetworkAuthFailure( 107 GoogleServiceAuthError( 108 GoogleServiceAuthError::HOSTED_NOT_ALLOWED))); 109 return; 110 } 111 112 if (error.state() == GoogleServiceAuthError::TWO_FACTOR) { 113 LOG(WARNING) << "Two factor authenticated. Sync will not work."; 114 TriggerResolve(LoginFailure::LoginFailureNone()); 115 116 return; 117 } 118 VLOG(2) << "ClientLogin attempt failed with " << error.state(); 119 TriggerResolve(LoginFailure::FromNetworkAuthFailure(error)); 120 } 121 122 void OnlineAttempt::TryClientLogin() { 123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 124 125 BrowserThread::PostDelayedTask( 126 BrowserThread::UI, FROM_HERE, 127 base::Bind(&OnlineAttempt::CancelClientLogin, weak_factory_.GetWeakPtr()), 128 base::TimeDelta::FromMilliseconds(kClientLoginTimeoutMs)); 129 130 client_fetcher_->StartClientLogin( 131 attempt_->user_context.username, 132 attempt_->user_context.password, 133 GaiaConstants::kSyncService, 134 attempt_->login_token, 135 attempt_->login_captcha, 136 attempt_->hosted_policy()); 137 } 138 139 bool OnlineAttempt::HasPendingFetch() { 140 return client_fetcher_->HasPendingFetch(); 141 } 142 143 void OnlineAttempt::CancelRequest() { 144 weak_factory_.InvalidateWeakPtrs(); 145 } 146 147 void OnlineAttempt::CancelClientLogin() { 148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 149 if (HasPendingFetch()) { 150 LOG(WARNING) << "Canceling ClientLogin attempt."; 151 CancelRequest(); 152 153 TriggerResolve(LoginFailure(LoginFailure::LOGIN_TIMED_OUT)); 154 } 155 } 156 157 void OnlineAttempt::TriggerResolve( 158 const LoginFailure& outcome) { 159 attempt_->RecordOnlineLoginStatus(outcome); 160 client_fetcher_.reset(NULL); 161 resolver_->Resolve(); 162 } 163 164 } // namespace chromeos 165