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.
5 #include "chrome/browser/chromeos/login/online_attempt.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"
27 using content::BrowserThread
;
32 const int OnlineAttempt::kClientLoginTimeoutMs
= 10000;
34 OnlineAttempt::OnlineAttempt(AuthAttemptState
* current_attempt
,
35 AuthAttemptStateResolver
* callback
)
36 : attempt_(current_attempt
),
40 DCHECK(attempt_
->user_type
== User::USER_TYPE_REGULAR
);
43 OnlineAttempt::~OnlineAttempt() {
45 if (client_fetcher_
.get())
46 client_fetcher_
->CancelRequest();
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()));
59 void OnlineAttempt::OnClientLoginSuccess(
60 const GaiaAuthConsumer::ClientLoginResult
& unused
) {
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
62 VLOG(1) << "Online login successful!";
64 weak_factory_
.InvalidateWeakPtrs();
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.
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
75 attempt_
->DisableHosted();
79 TriggerResolve(LoginFailure::LoginFailureNone());
82 void OnlineAttempt::OnClientLoginFailure(
83 const GoogleServiceAuthError
& error
) {
84 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
86 weak_factory_
.InvalidateWeakPtrs();
88 if (error
.state() == GoogleServiceAuthError::REQUEST_CANCELED
) {
91 // TODO(cmasone): add UMA tracking for this to see if we can remove it.
92 LOG(ERROR
) << "Login attempt canceled!?!? Trying again.";
96 LOG(ERROR
) << "Login attempt canceled again? Already retried...";
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
)));
112 if (error
.state() == GoogleServiceAuthError::TWO_FACTOR
) {
113 LOG(WARNING
) << "Two factor authenticated. Sync will not work.";
114 TriggerResolve(LoginFailure::LoginFailureNone());
118 VLOG(2) << "ClientLogin attempt failed with " << error
.state();
119 TriggerResolve(LoginFailure::FromNetworkAuthFailure(error
));
122 void OnlineAttempt::TryClientLogin() {
123 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
125 BrowserThread::PostDelayedTask(
126 BrowserThread::UI
, FROM_HERE
,
127 base::Bind(&OnlineAttempt::CancelClientLogin
, weak_factory_
.GetWeakPtr()),
128 base::TimeDelta::FromMilliseconds(kClientLoginTimeoutMs
));
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());
139 bool OnlineAttempt::HasPendingFetch() {
140 return client_fetcher_
->HasPendingFetch();
143 void OnlineAttempt::CancelRequest() {
144 weak_factory_
.InvalidateWeakPtrs();
147 void OnlineAttempt::CancelClientLogin() {
148 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
149 if (HasPendingFetch()) {
150 LOG(WARNING
) << "Canceling ClientLogin attempt.";
153 TriggerResolve(LoginFailure(LoginFailure::LOGIN_TIMED_OUT
));
157 void OnlineAttempt::TriggerResolve(
158 const LoginFailure
& outcome
) {
159 attempt_
->RecordOnlineLoginStatus(outcome
);
160 client_fetcher_
.reset(NULL
);
161 resolver_
->Resolve();
164 } // namespace chromeos