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 27namespace chromeos { 28 29// static 30const int OnlineAttempt::kClientLoginTimeoutMs = 10000; 31 32OnlineAttempt::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 42OnlineAttempt::~OnlineAttempt() { 43 // Just to be sure. 44 if (client_fetcher_.get()) 45 client_fetcher_->CancelRequest(); 46} 47 48void 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 56void 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 78void 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 114void 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 129bool OnlineAttempt::HasPendingFetch() { 130 return client_fetcher_->HasPendingFetch(); 131} 132 133void OnlineAttempt::CancelRequest() { 134 weak_factory_.InvalidateWeakPtrs(); 135} 136 137void OnlineAttempt::CancelClientLogin() { 138 if (HasPendingFetch()) { 139 LOG(WARNING) << "Canceling ClientLogin attempt."; 140 CancelRequest(); 141 142 TriggerResolve(AuthFailure(AuthFailure::LOGIN_TIMED_OUT)); 143 } 144} 145 146void OnlineAttempt::TriggerResolve(const AuthFailure& outcome) { 147 attempt_->RecordOnlineLoginStatus(outcome); 148 client_fetcher_.reset(NULL); 149 resolver_->Resolve(); 150} 151 152} // namespace chromeos 153