Home | History | Annotate | Download | only in login
      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 
     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 
     39 OnlineAttempt::~OnlineAttempt() {
     40   // Just to be sure.
     41   if (gaia_authenticator_.get())
     42     gaia_authenticator_->CancelRequest();
     43 }
     44 
     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 
     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 
     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 
    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 
    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 
    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