15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/auth_service.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
1158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/location.h"
126e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/message_loop/message_loop.h"
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/metrics/histogram.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "google_apis/drive/auth_service_observer.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "google_apis/gaia/google_service_auth_error.h"
164e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/url_request/url_request_context_getter.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace google_apis {
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace {
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Used for success ratio histograms. 0 for failure, 1 for success,
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// 2 for no connection (likely offline).
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kSuccessRatioHistogramFailure = 0;
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kSuccessRatioHistogramSuccess = 1;
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kSuccessRatioHistogramNoConnection = 2;
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kSuccessRatioHistogramTemporaryFailure = 3;
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kSuccessRatioHistogramMaxValue = 4;  // The max value is exclusive.
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
306e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void RecordAuthResultHistogram(int value) {
316e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  UMA_HISTOGRAM_ENUMERATION("GData.AuthSuccess",
326e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            value,
336e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                            kSuccessRatioHistogramMaxValue);
346e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)}
356e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
36868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)// OAuth2 authorization token retrieval request.
3758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochclass AuthRequest : public OAuth2TokenService::Consumer {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public:
39558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  AuthRequest(OAuth2TokenService* oauth2_token_service,
4068043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)              const std::string& account_id,
4158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch              net::URLRequestContextGetter* url_request_context_getter,
42868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)              const AuthStatusCallback& callback,
4358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch              const std::vector<std::string>& scopes);
44868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  virtual ~AuthRequest();
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch private:
4758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  // Overridden from OAuth2TokenService::Consumer:
4858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
4958e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                                 const std::string& access_token,
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                                 const base::Time& expiration_time) OVERRIDE;
5158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
5258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                                 const GoogleServiceAuthError& error) OVERRIDE;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  AuthStatusCallback callback_;
5558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  scoped_ptr<OAuth2TokenService::Request> request_;
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  base::ThreadChecker thread_checker_;
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
58868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(AuthRequest);
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)};
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
61868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)AuthRequest::AuthRequest(
62558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    OAuth2TokenService* oauth2_token_service,
6368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    net::URLRequestContextGetter* url_request_context_getter,
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const AuthStatusCallback& callback,
6658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch    const std::vector<std::string>& scopes)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    : OAuth2TokenService::Consumer("auth_service"),
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      callback_(callback) {
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  DCHECK(!callback_.is_null());
70558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  request_ = oauth2_token_service->
71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)      StartRequestWithContext(
7268043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)          account_id,
73a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          url_request_context_getter,
74a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          OAuth2TokenService::ScopeSet(scopes.begin(), scopes.end()),
75a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)          this);
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)AuthRequest::~AuthRequest() {}
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Callback for OAuth2AccessTokenFetcher on success. |access_token| is the token
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// used to start fetching user data.
8258e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid AuthRequest::OnGetTokenSuccess(const OAuth2TokenService::Request* request,
8358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                                    const std::string& access_token,
84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                                    const base::Time& expiration_time) {
85eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
876e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  RecordAuthResultHistogram(kSuccessRatioHistogramSuccess);
882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback_.Run(HTTP_SUCCESS, access_token);
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  delete this;
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Callback for OAuth2AccessTokenFetcher on failure.
9358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid AuthRequest::OnGetTokenFailure(const OAuth2TokenService::Request* request,
9458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                                    const GoogleServiceAuthError& error) {
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
97868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  LOG(WARNING) << "AuthRequest: token request using refresh token failed: "
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)               << error.ToString();
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // There are many ways to fail, but if the failure is due to connection,
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // it's likely that the device is off-line. We treat the error differently
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // so that the file manager works while off-line.
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
1046e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    RecordAuthResultHistogram(kSuccessRatioHistogramNoConnection);
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback_.Run(GDATA_NO_CONNECTION, std::string());
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
1076e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    RecordAuthResultHistogram(kSuccessRatioHistogramTemporaryFailure);
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback_.Run(HTTP_FORBIDDEN, std::string());
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Permanent auth error.
1116e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    RecordAuthResultHistogram(kSuccessRatioHistogramFailure);
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    callback_.Run(HTTP_UNAUTHORIZED, std::string());
1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
114c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  delete this;
1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
11758e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}  // namespace
11858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
1199ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben MurdochAuthService::AuthService(
120558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    OAuth2TokenService* oauth2_token_service,
12168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    const std::string& account_id,
1229ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    net::URLRequestContextGetter* url_request_context_getter,
1239ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch    const std::vector<std::string>& scopes)
124558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    : oauth2_token_service_(oauth2_token_service),
12568043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id_(account_id),
1269ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      url_request_context_getter_(url_request_context_getter),
1279ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      scopes_(scopes),
1289ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch      weak_ptr_factory_(this) {
129558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  DCHECK(oauth2_token_service);
1309ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Get OAuth2 refresh token (if we have any) and register for its updates.
132558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  oauth2_token_service_->AddObserver(this);
13368043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)  has_refresh_token_ = oauth2_token_service_->RefreshTokenIsAvailable(
13468043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)      account_id_);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)AuthService::~AuthService() {
138558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch  oauth2_token_service_->RemoveObserver(this);
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
141c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)void AuthService::StartAuthentication(const AuthStatusCallback& callback) {
142eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (HasAccessToken()) {
1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We already have access token. Give it back to the caller asynchronously.
1466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
1476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        FROM_HERE, base::Bind(callback, HTTP_SUCCESS, access_token_));
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else if (HasRefreshToken()) {
1492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // We have refresh token, let's get an access token.
150558790d6acca3451cf3a6b497803a5f07d0bec58Ben Murdoch    new AuthRequest(oauth2_token_service_,
15168043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)                    account_id_,
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                    url_request_context_getter_.get(),
15358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                    base::Bind(&AuthService::OnAuthCompleted,
15458e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                               weak_ptr_factory_.GetWeakPtr(),
15558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                               callback),
15658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch                    scopes_);
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    base::MessageLoop::current()->PostTask(
1596e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        FROM_HERE, base::Bind(callback, GDATA_NOT_READY, std::string()));
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AuthService::HasAccessToken() const {
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return !access_token_.empty();
1652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool AuthService::HasRefreshToken() const {
16858e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  return has_refresh_token_;
1692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const std::string& AuthService::access_token() const {
1722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return access_token_;
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AuthService::ClearAccessToken() {
1762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  access_token_.clear();
1772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void AuthService::ClearRefreshToken() {
1806e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  OnHandleRefreshToken(false);
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AuthService::OnAuthCompleted(const AuthStatusCallback& callback,
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  GDataErrorCode error,
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                  const std::string& access_token) {
186eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  DCHECK(thread_checker_.CalledOnValidThread());
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(!callback.is_null());
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (error == HTTP_SUCCESS) {
1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    access_token_ = access_token;
1912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else if (error == HTTP_UNAUTHORIZED) {
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Refreshing access token using the refresh token is failed with 401 error
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // (HTTP_UNAUTHORIZED). This means the current refresh token is invalid for
1942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Drive, hence we clear the refresh token here to make HasRefreshToken()
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // false, thus the invalidness is clearly observable.
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // This is not for triggering refetch of the refresh token. UI should
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // show some message to encourage user to log-off and log-in again in order
1982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // to fetch new valid refresh token.
1992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    ClearRefreshToken();
2002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  callback.Run(error, access_token);
2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AuthService::AddObserver(AuthServiceObserver* observer) {
2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.AddObserver(observer);
2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void AuthService::RemoveObserver(AuthServiceObserver* observer) {
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  observers_.RemoveObserver(observer);
2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
21358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid AuthService::OnRefreshTokenAvailable(const std::string& account_id) {
2146e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (account_id == account_id_)
2156e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    OnHandleRefreshToken(true);
21658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)void AuthService::OnRefreshTokenRevoked(const std::string& account_id) {
2196e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  if (account_id == account_id_)
2206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)    OnHandleRefreshToken(false);
22158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch}
2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
22358e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdochvoid AuthService::OnHandleRefreshToken(bool has_refresh_token) {
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  access_token_.clear();
22558e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch  has_refresh_token_ = has_refresh_token;
22658e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FOR_EACH_OBSERVER(AuthServiceObserver,
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    observers_,
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    OnOAuth2RefreshTokenChanged());
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace google_apis
233