1 // Copyright (c) 2013 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/oauth2_token_fetcher.h"
6
7 #include "base/logging.h"
8 #include "base/strings/string_util.h"
9 #include "chromeos/network/network_handler.h"
10 #include "chromeos/network/network_state.h"
11 #include "chromeos/network/network_state_handler.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "google_apis/gaia/gaia_constants.h"
14 #include "google_apis/gaia/google_service_auth_error.h"
15 #include "third_party/cros_system_api/dbus/service_constants.h"
16
17 using content::BrowserThread;
18
19 namespace {
20
21 // OAuth token request max retry count.
22 const int kMaxRequestAttemptCount = 5;
23 // OAuth token request retry delay in milliseconds.
24 const int kRequestRestartDelay = 3000;
25
26 } // namespace
27
28 namespace chromeos {
29
OAuth2TokenFetcher(OAuth2TokenFetcher::Delegate * delegate,net::URLRequestContextGetter * context_getter)30 OAuth2TokenFetcher::OAuth2TokenFetcher(
31 OAuth2TokenFetcher::Delegate* delegate,
32 net::URLRequestContextGetter* context_getter)
33 : delegate_(delegate),
34 auth_fetcher_(this, GaiaConstants::kChromeSource, context_getter),
35 retry_count_(0) {
36 DCHECK(delegate);
37 }
38
~OAuth2TokenFetcher()39 OAuth2TokenFetcher::~OAuth2TokenFetcher() {
40 }
41
StartExchangeFromCookies()42 void OAuth2TokenFetcher::StartExchangeFromCookies() {
43 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
44
45 // Delay the verification if the network is not connected or on a captive
46 // portal.
47 const NetworkState* default_network =
48 NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
49 if (!default_network ||
50 default_network->connection_state() == shill::kStatePortal) {
51 // If network is offline, defer the token fetching until online.
52 VLOG(1) << "Network is offline. Deferring OAuth2 token fetch.";
53 BrowserThread::PostDelayedTask(
54 BrowserThread::UI, FROM_HERE,
55 base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies,
56 AsWeakPtr()),
57 base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
58 return;
59 }
60 auth_fetcher_.StartCookieForOAuthLoginTokenExchange(std::string());
61 }
62
StartExchangeFromAuthCode(const std::string & auth_code)63 void OAuth2TokenFetcher::StartExchangeFromAuthCode(
64 const std::string& auth_code) {
65 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
66 auth_code_ = auth_code;
67 // Delay the verification if the network is not connected or on a captive
68 // portal.
69 const NetworkState* default_network =
70 NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
71 if (!default_network ||
72 default_network->connection_state() == shill::kStatePortal) {
73 // If network is offline, defer the token fetching until online.
74 VLOG(1) << "Network is offline. Deferring OAuth2 token fetch.";
75 BrowserThread::PostDelayedTask(
76 BrowserThread::UI, FROM_HERE,
77 base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode,
78 AsWeakPtr(),
79 auth_code),
80 base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
81 return;
82 }
83 auth_fetcher_.StartAuthCodeForOAuth2TokenExchange(auth_code);
84 }
85
OnClientOAuthSuccess(const GaiaAuthConsumer::ClientOAuthResult & oauth_tokens)86 void OAuth2TokenFetcher::OnClientOAuthSuccess(
87 const GaiaAuthConsumer::ClientOAuthResult& oauth_tokens) {
88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
89 VLOG(1) << "Got OAuth2 tokens!";
90 retry_count_ = 0;
91 oauth_tokens_ = oauth_tokens;
92 delegate_->OnOAuth2TokensAvailable(oauth_tokens_);
93 }
94
OnClientOAuthFailure(const GoogleServiceAuthError & error)95 void OAuth2TokenFetcher::OnClientOAuthFailure(
96 const GoogleServiceAuthError& error) {
97 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
98 RetryOnError(
99 error,
100 auth_code_.empty() ?
101 base::Bind(&OAuth2TokenFetcher::StartExchangeFromCookies,
102 AsWeakPtr()) :
103 base::Bind(&OAuth2TokenFetcher::StartExchangeFromAuthCode,
104 AsWeakPtr(), auth_code_),
105 base::Bind(&Delegate::OnOAuth2TokensFetchFailed,
106 base::Unretained(delegate_)));
107 }
108
RetryOnError(const GoogleServiceAuthError & error,const base::Closure & task,const base::Closure & error_handler)109 void OAuth2TokenFetcher::RetryOnError(const GoogleServiceAuthError& error,
110 const base::Closure& task,
111 const base::Closure& error_handler) {
112 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
113 if ((error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
114 error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
115 error.state() == GoogleServiceAuthError::REQUEST_CANCELED) &&
116 retry_count_ < kMaxRequestAttemptCount) {
117 retry_count_++;
118 BrowserThread::PostDelayedTask(
119 BrowserThread::UI, FROM_HERE, task,
120 base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
121 return;
122 }
123 LOG(ERROR) << "Unrecoverable error or retry count max reached. State: "
124 << error.state() << ", network error: " << error.network_error()
125 << ", message: " << error.error_message();
126 error_handler.Run();
127 }
128
129 } // namespace chromeos
130