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