• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/auth/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/auth_attempt_state.h"
14 #include "chrome/browser/chromeos/login/auth/auth_attempt_state_resolver.h"
15 #include "chrome/browser/chromeos/login/auth/key.h"
16 #include "chrome/browser/chromeos/login/auth/user_context.h"
17 #include "chrome/browser/chromeos/login/users/user.h"
18 #include "content/public/browser/browser_context.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "google_apis/gaia/gaia_auth_consumer.h"
21 #include "google_apis/gaia/gaia_auth_fetcher.h"
22 #include "google_apis/gaia/gaia_constants.h"
23 #include "net/base/load_flags.h"
24 #include "net/base/net_errors.h"
25 #include "net/url_request/url_request_status.h"
26 
27 using content::BrowserThread;
28 
29 namespace chromeos {
30 
31 // static
32 const int OnlineAttempt::kClientLoginTimeoutMs = 10000;
33 
OnlineAttempt(AuthAttemptState * current_attempt,AuthAttemptStateResolver * callback)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 
~OnlineAttempt()43 OnlineAttempt::~OnlineAttempt() {
44   // Just to be sure.
45   if (client_fetcher_.get())
46     client_fetcher_->CancelRequest();
47 }
48 
Initiate(content::BrowserContext * auth_context)49 void OnlineAttempt::Initiate(content::BrowserContext* auth_context) {
50   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
51   client_fetcher_.reset(
52       new GaiaAuthFetcher(this, GaiaConstants::kChromeOSSource,
53                           auth_context->GetRequestContext()));
54   BrowserThread::PostTask(
55       BrowserThread::UI, FROM_HERE,
56       base::Bind(&OnlineAttempt::TryClientLogin, weak_factory_.GetWeakPtr()));
57 }
58 
OnClientLoginSuccess(const GaiaAuthConsumer::ClientLoginResult & unused)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 
OnClientLoginFailure(const GoogleServiceAuthError & error)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 
TryClientLogin()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.GetUserID(),
132       attempt_->user_context.GetKey()->GetSecret(),
133       GaiaConstants::kSyncService,
134       attempt_->login_token,
135       attempt_->login_captcha,
136       attempt_->hosted_policy());
137 }
138 
HasPendingFetch()139 bool OnlineAttempt::HasPendingFetch() {
140   return client_fetcher_->HasPendingFetch();
141 }
142 
CancelRequest()143 void OnlineAttempt::CancelRequest() {
144   weak_factory_.InvalidateWeakPtrs();
145 }
146 
CancelClientLogin()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 
TriggerResolve(const LoginFailure & outcome)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