1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// found in the LICENSE file.
4868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "chrome/browser/supervised_user/supervised_user_refresh_token_fetcher.h"
6868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/callback.h"
8868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/json/json_reader.h"
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/logging.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/stringprintf.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/values.h"
12eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "google_apis/gaia/gaia_constants.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "google_apis/gaia/gaia_oauth_client.h"
14868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "google_apis/gaia/gaia_urls.h"
15868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h"
16868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "google_apis/gaia/oauth2_api_call_flow.h"
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "google_apis/gaia/oauth2_token_service.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/base/escape.h"
19868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/base/load_flags.h"
20868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/base/net_errors.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/http/http_status_code.h"
22868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/url_request/url_fetcher.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "net/url_request/url_request_status.h"
24868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)using GaiaConstants::kChromeSyncSupervisedOAuth2Scope;
26868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using base::Time;
27868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using gaia::GaiaOAuthClient;
28868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using net::URLFetcher;
29868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using net::URLFetcherDelegate;
30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)using net::URLRequestContextGetter;
31868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
32868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)namespace {
33868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
34868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)const int kNumRetries = 1;
35868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static const char kIssueTokenBodyFormat[] =
37868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "client_id=%s"
38868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "&scope=%s"
39868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "&response_type=code"
40868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "&profile_id=%s"
41868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "&device_name=%s";
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// kIssueTokenBodyFormatDeviceIdAddendum is appended to kIssueTokenBodyFormat
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// if device_id is provided.
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)static const char kIssueTokenBodyFormatDeviceIdAddendum[] = "&device_id=%s";
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static const char kAuthorizationHeaderFormat[] =
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    "Authorization: Bearer %s";
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)static const char kCodeKey[] = "code";
51868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
52f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class SupervisedUserRefreshTokenFetcherImpl
53f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : public SupervisedUserRefreshTokenFetcher,
54868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      public OAuth2TokenService::Consumer,
55868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      public URLFetcherDelegate,
56868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      public GaiaOAuthClient::Delegate {
57868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) public:
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  SupervisedUserRefreshTokenFetcherImpl(
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      OAuth2TokenService* oauth2_token_service,
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      const std::string& account_id,
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const std::string& device_id,
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      URLRequestContextGetter* context);
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual ~SupervisedUserRefreshTokenFetcherImpl();
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // SupervisedUserRefreshTokenFetcher implementation:
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  virtual void Start(const std::string& supervised_user_id,
67868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     const std::string& device_name,
68868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     const TokenCallback& callback) OVERRIDE;
69868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
70868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) protected:
71868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // OAuth2TokenService::Consumer implementation:
72868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
73868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 const std::string& access_token,
74868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 const Time& expiration_time) OVERRIDE;
75868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
76868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 const GoogleServiceAuthError& error) OVERRIDE;
77868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // net::URLFetcherDelegate implementation.
79868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void OnURLFetchComplete(const URLFetcher* source) OVERRIDE;
80868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
81868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // GaiaOAuthClient::Delegate implementation:
82868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void OnGetTokensResponse(const std::string& refresh_token,
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                   const std::string& access_token,
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                   int expires_in_seconds) OVERRIDE;
85868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void OnRefreshTokenResponse(const std::string& access_token,
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      int expires_in_seconds) OVERRIDE;
87868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void OnOAuthError() OVERRIDE;
88868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual void OnNetworkError(int response_code) OVERRIDE;
89868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
90868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) private:
91868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // Requests an access token, which is the first thing we need. This is where
92868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // we restart when the returned access token has expired.
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  void StartFetching();
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  void DispatchNetworkError(int error_code);
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  void DispatchGoogleServiceAuthError(const GoogleServiceAuthError& error,
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                      const std::string& token);
98868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  OAuth2TokenService* oauth2_token_service_;
9968043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  std::string account_id_;
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string device_id_;
101868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  URLRequestContextGetter* context_;
102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
103868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string device_name_;
104f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  std::string supervised_user_id_;
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  TokenCallback callback_;
106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
107868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<OAuth2TokenService::Request> access_token_request_;
108868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string access_token_;
109868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  bool access_token_expired_;
110868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<URLFetcher> url_fetcher_;
111868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<GaiaOAuthClient> gaia_oauth_client_;
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)};
113868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserRefreshTokenFetcherImpl::SupervisedUserRefreshTokenFetcherImpl(
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    OAuth2TokenService* oauth2_token_service,
11668043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& device_id,
118868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    URLRequestContextGetter* context)
119f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    : OAuth2TokenService::Consumer("supervised_user"),
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      oauth2_token_service_(oauth2_token_service),
12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id_(account_id),
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      device_id_(device_id),
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      context_(context),
124868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      access_token_expired_(false) {}
125868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
126f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserRefreshTokenFetcherImpl::
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)~SupervisedUserRefreshTokenFetcherImpl() {}
128868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
129f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::Start(
130f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& supervised_user_id,
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& device_name,
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const TokenCallback& callback) {
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK(callback_.is_null());
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  supervised_user_id_ = supervised_user_id;
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  device_name_ = device_name;
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callback_ = callback;
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  StartFetching();
138868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
140f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::StartFetching() {
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  OAuth2TokenService::ScopeSet scopes;
142a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  scopes.insert(GaiaConstants::kOAuth1LoginScope);
14368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  access_token_request_ = oauth2_token_service_->StartRequest(
14468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id_, scopes, this);
145868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
147f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::OnGetTokenSuccess(
148868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const OAuth2TokenService::Request* request,
149868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& access_token,
150868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const Time& expiration_time) {
151868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(access_token_request_.get(), request);
152868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  access_token_ = access_token;
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  GURL url(GaiaUrls::GetInstance()->oauth2_issue_token_url());
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // GaiaOAuthClient uses id 0, so we use 1 to distinguish the requests in
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // unit tests.
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const int id = 1;
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
159868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  url_fetcher_.reset(URLFetcher::Create(id, url, URLFetcher::POST, this));
160868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
161868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  url_fetcher_->SetRequestContext(context_);
162868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
163868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                             net::LOAD_DO_NOT_SAVE_COOKIES);
164868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(kNumRetries);
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  url_fetcher_->AddExtraRequestHeader(
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str()));
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string body = base::StringPrintf(
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      kIssueTokenBodyFormat,
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      net::EscapeUrlEncodedData(
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          GaiaUrls::GetInstance()->oauth2_chrome_client_id(), true).c_str(),
172f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      net::EscapeUrlEncodedData(kChromeSyncSupervisedOAuth2Scope, true).c_str(),
173f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      net::EscapeUrlEncodedData(supervised_user_id_, true).c_str(),
174868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      net::EscapeUrlEncodedData(device_name_, true).c_str());
1755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!device_id_.empty()) {
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    body.append(base::StringPrintf(
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        kIssueTokenBodyFormatDeviceIdAddendum,
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        net::EscapeUrlEncodedData(device_id_, true).c_str()));
1795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
180868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  url_fetcher_->SetUploadData("application/x-www-form-urlencoded", body);
181868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
182868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  url_fetcher_->Start();
183868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
184868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
185f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::OnGetTokenFailure(
186868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const OAuth2TokenService::Request* request,
187868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const GoogleServiceAuthError& error) {
188868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DCHECK_EQ(access_token_request_.get(), request);
189868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callback_.Run(error, std::string());
190868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callback_.Reset();
191868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
192868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
193f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::OnURLFetchComplete(
194868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const URLFetcher* source) {
195868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  const net::URLRequestStatus& status = source->GetStatus();
196868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!status.is_success()) {
197868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DispatchNetworkError(status.error());
198868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
199868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
200868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
201868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  int response_code = source->GetResponseCode();
202868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (response_code == net::HTTP_UNAUTHORIZED && !access_token_expired_) {
203868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    access_token_expired_ = true;
20468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    oauth2_token_service_->InvalidateToken(account_id_,
20568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                                           OAuth2TokenService::ScopeSet(),
206868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                           access_token_);
207868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    StartFetching();
208868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
209868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
210868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
211868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (response_code != net::HTTP_OK) {
212868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // TODO(bauerb): We should return the HTTP response code somehow.
213868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DLOG(WARNING) << "HTTP error " << response_code;
214868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DispatchGoogleServiceAuthError(
215868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
216868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)        std::string());
217868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
218868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
219868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
220868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string response_body;
221868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  source->GetResponseAsString(&response_body);
222868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  scoped_ptr<base::Value> value(base::JSONReader::Read(response_body));
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  base::DictionaryValue* dict = NULL;
224868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!value.get() || !value->GetAsDictionary(&dict)) {
225868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DispatchNetworkError(net::ERR_INVALID_RESPONSE);
226868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
227868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
228868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  std::string auth_code;
229868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  if (!dict->GetString(kCodeKey, &auth_code)) {
230868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    DispatchNetworkError(net::ERR_INVALID_RESPONSE);
231868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    return;
232868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  }
233868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
234868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gaia::OAuthClientInfo client_info;
235868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  GaiaUrls* urls = GaiaUrls::GetInstance();
236868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  client_info.client_id = urls->oauth2_chrome_client_id();
237868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  client_info.client_secret = urls->oauth2_chrome_client_secret();
238eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  gaia_oauth_client_.reset(new gaia::GaiaOAuthClient(context_));
239868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  gaia_oauth_client_->GetTokensFromAuthCode(client_info, auth_code, kNumRetries,
240868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                            this);
241868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
242868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
243f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::OnGetTokensResponse(
244868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& refresh_token,
245868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& access_token,
246868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int expires_in_seconds) {
247868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // TODO(bauerb): It would be nice if we could pass the access token as well,
248868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // so we don't need to fetch another one immediately.
249868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DispatchGoogleServiceAuthError(GoogleServiceAuthError::AuthErrorNone(),
250868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                 refresh_token);
251868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
252868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
253f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::OnRefreshTokenResponse(
254868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& access_token,
255868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int expires_in_seconds) {
256868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  NOTREACHED();
257868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
258868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
259f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::OnOAuthError() {
260868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DispatchGoogleServiceAuthError(
261868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
262868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string());
263868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
264868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
265f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::OnNetworkError(int response_code) {
266868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  // TODO(bauerb): We should return the HTTP response code somehow.
267868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DLOG(WARNING) << "HTTP error " << response_code;
268868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DispatchGoogleServiceAuthError(
269868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      GoogleServiceAuthError(GoogleServiceAuthError::CONNECTION_FAILED),
270868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      std::string());
271868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
272868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
273f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::DispatchNetworkError(
274f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    int error_code) {
275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DispatchGoogleServiceAuthError(
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      GoogleServiceAuthError::FromConnectionError(error_code), std::string());
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
279f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void SupervisedUserRefreshTokenFetcherImpl::DispatchGoogleServiceAuthError(
280868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const GoogleServiceAuthError& error,
281868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const std::string& token) {
282868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callback_.Run(error, token);
283868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  callback_.Reset();
284868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
285868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
286868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}  // namespace
287868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
288868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// static
289f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)scoped_ptr<SupervisedUserRefreshTokenFetcher>
290f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserRefreshTokenFetcher::Create(
291f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    OAuth2TokenService* oauth2_token_service,
292f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    const std::string& account_id,
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& device_id,
294f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    URLRequestContextGetter* context) {
295f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  scoped_ptr<SupervisedUserRefreshTokenFetcher> fetcher(
296f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)      new SupervisedUserRefreshTokenFetcherImpl(oauth2_token_service,
297f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                                account_id,
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                                device_id,
299f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                                context));
300868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  return fetcher.Pass();
301868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)}
302868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
303f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)SupervisedUserRefreshTokenFetcher::~SupervisedUserRefreshTokenFetcher() {}
304