policy_oauth2_token_fetcher.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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/policy/policy_oauth2_token_fetcher.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/logging.h"
11#include "base/strings/string_util.h"
12#include "content/public/browser/browser_thread.h"
13#include "google_apis/gaia/gaia_auth_fetcher.h"
14#include "google_apis/gaia/gaia_constants.h"
15#include "google_apis/gaia/gaia_urls.h"
16#include "google_apis/gaia/google_service_auth_error.h"
17#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
18#include "net/url_request/url_request_context_getter.h"
19
20using content::BrowserThread;
21
22namespace policy {
23
24namespace {
25
26// Max retry count for token fetching requests.
27const int kMaxRequestAttemptCount = 5;
28
29// OAuth token request retry delay in milliseconds.
30const int kRequestRestartDelay = 3000;
31
32}  // namespace
33
34PolicyOAuth2TokenFetcher::PolicyOAuth2TokenFetcher(
35    net::URLRequestContextGetter* auth_context_getter,
36    net::URLRequestContextGetter* system_context_getter,
37    const TokenCallback& callback)
38    : auth_context_getter_(auth_context_getter),
39      system_context_getter_(system_context_getter),
40      retry_count_(0),
41      failed_(false),
42      callback_(callback) {}
43
44PolicyOAuth2TokenFetcher::~PolicyOAuth2TokenFetcher() {}
45
46void PolicyOAuth2TokenFetcher::Start() {
47  retry_count_ = 0;
48  StartFetchingRefreshToken();
49}
50
51void PolicyOAuth2TokenFetcher::StartFetchingRefreshToken() {
52  refresh_token_fetcher_.reset(new GaiaAuthFetcher(
53      this, GaiaConstants::kChromeSource, auth_context_getter_.get()));
54  refresh_token_fetcher_->StartCookieForOAuthLoginTokenExchange(std::string());
55}
56
57void PolicyOAuth2TokenFetcher::StartFetchingAccessToken() {
58  std::vector<std::string> scopes;
59  scopes.push_back(GaiaConstants::kDeviceManagementServiceOAuth);
60  scopes.push_back(GaiaConstants::kOAuthWrapBridgeUserInfoScope);
61  scopes.push_back(GaiaConstants::kGoogleUserInfoEmail);
62  scopes.push_back(GaiaConstants::kGoogleUserInfoProfile);
63  access_token_fetcher_.reset(
64      new OAuth2AccessTokenFetcherImpl(this,
65                                       system_context_getter_.get(),
66                                       oauth2_refresh_token_));
67  access_token_fetcher_->Start(
68      GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
69      GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
70      scopes);
71}
72
73void PolicyOAuth2TokenFetcher::OnClientOAuthSuccess(
74    const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) {
75  VLOG(1) << "OAuth2 tokens for policy fetching succeeded.";
76  oauth2_refresh_token_ = oauth2_tokens.refresh_token;
77  retry_count_ = 0;
78  StartFetchingAccessToken();
79}
80
81void PolicyOAuth2TokenFetcher::OnClientOAuthFailure(
82    const GoogleServiceAuthError& error) {
83  VLOG(1) << "OAuth2 tokens fetch for policy fetch failed!";
84  RetryOnError(error,
85               base::Bind(&PolicyOAuth2TokenFetcher::StartFetchingRefreshToken,
86                          AsWeakPtr()));
87}
88
89void PolicyOAuth2TokenFetcher::OnGetTokenSuccess(
90    const std::string& access_token,
91    const base::Time& expiration_time) {
92  VLOG(1) << "OAuth2 access token (device management) fetching succeeded.";
93  oauth2_access_token_ = access_token;
94  ForwardPolicyToken(access_token,
95                     GoogleServiceAuthError(GoogleServiceAuthError::NONE));
96}
97
98void PolicyOAuth2TokenFetcher::OnGetTokenFailure(
99    const GoogleServiceAuthError& error) {
100  LOG(ERROR) << "OAuth2 access token (device management) fetching failed!";
101  RetryOnError(error,
102               base::Bind(&PolicyOAuth2TokenFetcher::StartFetchingAccessToken,
103                          AsWeakPtr()));
104}
105
106void PolicyOAuth2TokenFetcher::RetryOnError(const GoogleServiceAuthError& error,
107                                            const base::Closure& task) {
108  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
109  if ((error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
110       error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
111       error.state() == GoogleServiceAuthError::REQUEST_CANCELED) &&
112      retry_count_ < kMaxRequestAttemptCount) {
113    retry_count_++;
114    BrowserThread::PostDelayedTask(
115        BrowserThread::UI, FROM_HERE, task,
116        base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
117    return;
118  }
119  LOG(ERROR) << "Unrecoverable error or retry count max reached.";
120  failed_ = true;
121  // Invoking the |callback_| signals to the owner of this object that it has
122  // completed, and the owner may delete this object on the callback method.
123  // So don't rely on |this| still being valid after ForwardPolicyToken()
124  // returns i.e. don't write to |failed_| or other fields.
125  ForwardPolicyToken(std::string(), error);
126}
127
128void PolicyOAuth2TokenFetcher::ForwardPolicyToken(
129    const std::string& token,
130    const GoogleServiceAuthError& error) {
131  if (!callback_.is_null())
132    callback_.Run(token, error);
133}
134
135}  // namespace policy
136