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