auth_service.cc 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. // Copyright (c) 2012 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. #include "google_apis/common/auth_service.h"
  5. #include <string>
  6. #include <vector>
  7. #include "base/bind.h"
  8. #include "base/location.h"
  9. #include "base/memory/raw_ptr.h"
  10. #include "base/metrics/histogram_macros.h"
  11. #include "base/observer_list.h"
  12. #include "base/scoped_observation.h"
  13. #include "base/task/single_thread_task_runner.h"
  14. #include "base/threading/thread_task_runner_handle.h"
  15. #include "components/signin/public/identity_manager/access_token_fetcher.h"
  16. #include "components/signin/public/identity_manager/access_token_info.h"
  17. #include "components/signin/public/identity_manager/identity_manager.h"
  18. #include "components/signin/public/identity_manager/scope_set.h"
  19. #include "google_apis/common/auth_service_observer.h"
  20. #include "google_apis/gaia/google_service_auth_error.h"
  21. #include "services/network/public/cpp/shared_url_loader_factory.h"
  22. namespace google_apis {
  23. namespace {
  24. // Used for success ratio histograms. 0 for failure, 1 for success,
  25. // 2 for no connection (likely offline).
  26. const int kSuccessRatioHistogramFailure = 0;
  27. const int kSuccessRatioHistogramSuccess = 1;
  28. const int kSuccessRatioHistogramNoConnection = 2;
  29. const int kSuccessRatioHistogramTemporaryFailure = 3;
  30. const int kSuccessRatioHistogramMaxValue = 4; // The max value is exclusive.
  31. void RecordAuthResultHistogram(int value) {
  32. UMA_HISTOGRAM_ENUMERATION("GData.AuthSuccess", value,
  33. kSuccessRatioHistogramMaxValue);
  34. }
  35. // OAuth2 authorization token retrieval request.
  36. class AuthRequest {
  37. public:
  38. AuthRequest(signin::IdentityManager* identity_manager,
  39. const CoreAccountId& account_id,
  40. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
  41. AuthStatusCallback callback,
  42. const std::vector<std::string>& scopes);
  43. AuthRequest(const AuthRequest&) = delete;
  44. AuthRequest& operator=(const AuthRequest&) = delete;
  45. ~AuthRequest();
  46. private:
  47. void OnAccessTokenFetchComplete(GoogleServiceAuthError error,
  48. signin::AccessTokenInfo token_info);
  49. AuthStatusCallback callback_;
  50. std::unique_ptr<signin::AccessTokenFetcher> access_token_fetcher_;
  51. base::ThreadChecker thread_checker_;
  52. };
  53. AuthRequest::AuthRequest(
  54. signin::IdentityManager* identity_manager,
  55. const CoreAccountId& account_id,
  56. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
  57. AuthStatusCallback callback,
  58. const std::vector<std::string>& scopes)
  59. : callback_(std::move(callback)) {
  60. DCHECK(identity_manager);
  61. DCHECK(callback_);
  62. access_token_fetcher_ = identity_manager->CreateAccessTokenFetcherForAccount(
  63. account_id, "auth_service", url_loader_factory,
  64. signin::ScopeSet(scopes.begin(), scopes.end()),
  65. base::BindOnce(&AuthRequest::OnAccessTokenFetchComplete,
  66. base::Unretained(this)),
  67. signin::AccessTokenFetcher::Mode::kImmediate);
  68. }
  69. AuthRequest::~AuthRequest() {}
  70. void AuthRequest::OnAccessTokenFetchComplete(
  71. GoogleServiceAuthError error,
  72. signin::AccessTokenInfo token_info) {
  73. DCHECK(thread_checker_.CalledOnValidThread());
  74. if (error.state() == GoogleServiceAuthError::NONE) {
  75. RecordAuthResultHistogram(kSuccessRatioHistogramSuccess);
  76. std::move(callback_).Run(HTTP_SUCCESS, token_info.token);
  77. } else {
  78. LOG(WARNING) << "AuthRequest: token request using refresh token failed: "
  79. << error.ToString();
  80. // There are many ways to fail, but if the failure is due to connection,
  81. // it's likely that the device is off-line. We treat the error differently
  82. // so that the file manager works while off-line.
  83. if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
  84. RecordAuthResultHistogram(kSuccessRatioHistogramNoConnection);
  85. std::move(callback_).Run(NO_CONNECTION, std::string());
  86. } else if (error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
  87. RecordAuthResultHistogram(kSuccessRatioHistogramTemporaryFailure);
  88. std::move(callback_).Run(HTTP_FORBIDDEN, std::string());
  89. } else {
  90. // Permanent auth error.
  91. RecordAuthResultHistogram(kSuccessRatioHistogramFailure);
  92. std::move(callback_).Run(HTTP_UNAUTHORIZED, std::string());
  93. }
  94. }
  95. delete this;
  96. }
  97. } // namespace
  98. // This class is separate from AuthService itself so that AuthService doesn't
  99. // need a public dependency on signin::IdentityManager::Observer, and therefore
  100. // doesn't need to pull that dependency into all of its client classes.
  101. class AuthService::IdentityManagerObserver
  102. : public signin::IdentityManager::Observer {
  103. public:
  104. explicit IdentityManagerObserver(AuthService* service) : service_(service) {
  105. manager_observation_.Observe(service->identity_manager_.get());
  106. }
  107. ~IdentityManagerObserver() override = default;
  108. // signin::IdentityManager::Observer:
  109. void OnRefreshTokenUpdatedForAccount(
  110. const CoreAccountInfo& account_info) override {
  111. service_->OnHandleRefreshToken(account_info.account_id, true);
  112. }
  113. void OnRefreshTokenRemovedForAccount(
  114. const CoreAccountId& account_id) override {
  115. service_->OnHandleRefreshToken(account_id, false);
  116. }
  117. private:
  118. raw_ptr<AuthService> service_ = nullptr;
  119. base::ScopedObservation<signin::IdentityManager,
  120. signin::IdentityManager::Observer>
  121. manager_observation_{this};
  122. };
  123. AuthService::AuthService(
  124. signin::IdentityManager* identity_manager,
  125. const CoreAccountId& account_id,
  126. scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
  127. const std::vector<std::string>& scopes)
  128. : identity_manager_(identity_manager),
  129. identity_manager_observer_(
  130. std::make_unique<IdentityManagerObserver>(this)),
  131. account_id_(account_id),
  132. url_loader_factory_(url_loader_factory),
  133. scopes_(scopes) {
  134. DCHECK(identity_manager_);
  135. has_refresh_token_ =
  136. identity_manager_->HasAccountWithRefreshToken(account_id_);
  137. }
  138. AuthService::~AuthService() = default;
  139. void AuthService::StartAuthentication(AuthStatusCallback callback) {
  140. DCHECK(thread_checker_.CalledOnValidThread());
  141. if (HasAccessToken()) {
  142. // We already have access token. Give it back to the caller asynchronously.
  143. base::ThreadTaskRunnerHandle::Get()->PostTask(
  144. FROM_HERE,
  145. base::BindOnce(std::move(callback), HTTP_SUCCESS, access_token_));
  146. } else if (HasRefreshToken()) {
  147. // We have refresh token, let's get an access token.
  148. new AuthRequest(
  149. identity_manager_, account_id_, url_loader_factory_,
  150. base::BindOnce(&AuthService::OnAuthCompleted,
  151. weak_ptr_factory_.GetWeakPtr(), std::move(callback)),
  152. scopes_);
  153. } else {
  154. base::ThreadTaskRunnerHandle::Get()->PostTask(
  155. FROM_HERE,
  156. base::BindOnce(std::move(callback), NOT_READY, std::string()));
  157. }
  158. }
  159. bool AuthService::HasAccessToken() const {
  160. return !access_token_.empty();
  161. }
  162. bool AuthService::HasRefreshToken() const {
  163. return has_refresh_token_;
  164. }
  165. const std::string& AuthService::access_token() const {
  166. return access_token_;
  167. }
  168. void AuthService::ClearAccessToken() {
  169. access_token_.clear();
  170. }
  171. void AuthService::ClearRefreshToken() {
  172. OnHandleRefreshToken(account_id_, false);
  173. }
  174. void AuthService::OnAuthCompleted(AuthStatusCallback callback,
  175. ApiErrorCode error,
  176. const std::string& access_token) {
  177. DCHECK(thread_checker_.CalledOnValidThread());
  178. DCHECK(callback);
  179. if (error == HTTP_SUCCESS) {
  180. access_token_ = access_token;
  181. } else if (error == HTTP_UNAUTHORIZED) {
  182. // Refreshing access token using the refresh token is failed with 401 error
  183. // (HTTP_UNAUTHORIZED). This means the current refresh token is invalid for
  184. // the current scope, hence we clear the refresh token here to make
  185. // HasRefreshToken() false, thus the invalidness is clearly observable.
  186. // This is not for triggering refetch of the refresh token. UI should
  187. // show some message to encourage user to log-off and log-in again in order
  188. // to fetch new valid refresh token.
  189. ClearRefreshToken();
  190. }
  191. std::move(callback).Run(error, access_token);
  192. }
  193. void AuthService::AddObserver(AuthServiceObserver* observer) {
  194. observers_.AddObserver(observer);
  195. }
  196. void AuthService::RemoveObserver(AuthServiceObserver* observer) {
  197. observers_.RemoveObserver(observer);
  198. }
  199. void AuthService::OnHandleRefreshToken(const CoreAccountId& account_id,
  200. bool has_refresh_token) {
  201. if (account_id != account_id_)
  202. return;
  203. access_token_.clear();
  204. has_refresh_token_ = has_refresh_token;
  205. for (auto& observer : observers_)
  206. observer.OnOAuth2RefreshTokenChanged();
  207. }
  208. } // namespace google_apis