1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/chromeos/policy/policy_oauth2_token_fetcher.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include <vector>
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/bind.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
115e3f23d412006dc4db4e659864679f29341e113fTorne (Richard Coles)#include "base/strings/string_util.h"
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/gaia_auth_fetcher.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/gaia_constants.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h"
17a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "google_apis/gaia/oauth2_access_token_fetcher_impl.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread;
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)namespace policy {
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Max retry count for token fetching requests.
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kMaxRequestAttemptCount = 5;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// OAuth token request retry delay in milliseconds.
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kRequestRestartDelay = 3000;
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)PolicyOAuth2TokenFetcher::PolicyOAuth2TokenFetcher(
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequestContextGetter* auth_context_getter,
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    net::URLRequestContextGetter* system_context_getter,
37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const TokenCallback& callback)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : auth_context_getter_(auth_context_getter),
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      system_context_getter_(system_context_getter),
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      retry_count_(0),
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      failed_(false),
42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      callback_(callback) {}
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)PolicyOAuth2TokenFetcher::~PolicyOAuth2TokenFetcher() {}
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PolicyOAuth2TokenFetcher::Start() {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  retry_count_ = 0;
48a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  StartFetchingRefreshToken();
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PolicyOAuth2TokenFetcher::StartFetchingRefreshToken() {
527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  refresh_token_fetcher_.reset(new GaiaAuthFetcher(
537d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      this, GaiaConstants::kChromeSource, auth_context_getter_.get()));
54f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  refresh_token_fetcher_->StartCookieForOAuthLoginTokenExchange(std::string());
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PolicyOAuth2TokenFetcher::StartFetchingAccessToken() {
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<std::string> scopes;
59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scopes.push_back(GaiaConstants::kDeviceManagementServiceOAuth);
60a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scopes.push_back(GaiaConstants::kOAuthWrapBridgeUserInfoScope);
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  access_token_fetcher_.reset(
62a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      new OAuth2AccessTokenFetcherImpl(this,
63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                       system_context_getter_.get(),
64a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                       oauth2_refresh_token_));
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  access_token_fetcher_->Start(
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_id(),
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      GaiaUrls::GetInstance()->oauth2_chrome_client_secret(),
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      scopes);
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PolicyOAuth2TokenFetcher::OnClientOAuthSuccess(
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GaiaAuthConsumer::ClientOAuthResult& oauth2_tokens) {
73f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VLOG(1) << "OAuth2 tokens for policy fetching succeeded.";
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  oauth2_refresh_token_ = oauth2_tokens.refresh_token;
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  retry_count_ = 0;
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  StartFetchingAccessToken();
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PolicyOAuth2TokenFetcher::OnClientOAuthFailure(
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GoogleServiceAuthError& error) {
81f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VLOG(1) << "OAuth2 tokens fetch for policy fetch failed!";
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RetryOnError(error,
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               base::Bind(&PolicyOAuth2TokenFetcher::StartFetchingRefreshToken,
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          AsWeakPtr()));
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PolicyOAuth2TokenFetcher::OnGetTokenSuccess(
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& access_token,
892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const base::Time& expiration_time) {
90f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  VLOG(1) << "OAuth2 access token (device management) fetching succeeded.";
91558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  oauth2_access_token_ = access_token;
92558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  ForwardPolicyToken(access_token,
93558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch                     GoogleServiceAuthError(GoogleServiceAuthError::NONE));
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PolicyOAuth2TokenFetcher::OnGetTokenFailure(
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GoogleServiceAuthError& error) {
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG(ERROR) << "OAuth2 access token (device management) fetching failed!";
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  RetryOnError(error,
100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)               base::Bind(&PolicyOAuth2TokenFetcher::StartFetchingAccessToken,
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                          AsWeakPtr()));
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void PolicyOAuth2TokenFetcher::RetryOnError(const GoogleServiceAuthError& error,
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)                                            const base::Closure& task) {
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if ((error.state() == GoogleServiceAuthError::CONNECTION_FAILED ||
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE ||
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       error.state() == GoogleServiceAuthError::REQUEST_CANCELED) &&
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      retry_count_ < kMaxRequestAttemptCount) {
1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    retry_count_++;
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    BrowserThread::PostDelayedTask(
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        BrowserThread::UI, FROM_HERE, task,
1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::TimeDelta::FromMilliseconds(kRequestRestartDelay));
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return;
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  LOG(ERROR) << "Unrecoverable error or retry count max reached.";
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  failed_ = true;
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Invoking the |callback_| signals to the owner of this object that it has
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // completed, and the owner may delete this object on the callback method.
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // So don't rely on |this| still being valid after ForwardPolicyToken()
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // returns i.e. don't write to |failed_| or other fields.
123558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  ForwardPolicyToken(std::string(), error);
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
126558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdochvoid PolicyOAuth2TokenFetcher::ForwardPolicyToken(
127558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    const std::string& token,
128558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    const GoogleServiceAuthError& error) {
129558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  if (!callback_.is_null())
130558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    callback_.Run(token, error);
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)}  // namespace policy
134