Add ICU message format support
[chromium-blink-merge.git] / google_apis / drive / auth_service.cc
blob0fbc1327c960832cae77d676b28f8420eb542335
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.
5 #include "google_apis/drive/auth_service.h"
7 #include <string>
8 #include <vector>
10 #include "base/bind.h"
11 #include "base/location.h"
12 #include "base/message_loop/message_loop.h"
13 #include "base/metrics/histogram.h"
14 #include "google_apis/drive/auth_service_observer.h"
15 #include "google_apis/gaia/google_service_auth_error.h"
16 #include "net/url_request/url_request_context_getter.h"
18 namespace google_apis {
20 namespace {
22 // Used for success ratio histograms. 0 for failure, 1 for success,
23 // 2 for no connection (likely offline).
24 const int kSuccessRatioHistogramFailure = 0;
25 const int kSuccessRatioHistogramSuccess = 1;
26 const int kSuccessRatioHistogramNoConnection = 2;
27 const int kSuccessRatioHistogramTemporaryFailure = 3;
28 const int kSuccessRatioHistogramMaxValue = 4; // The max value is exclusive.
30 void RecordAuthResultHistogram(int value) {
31 UMA_HISTOGRAM_ENUMERATION("GData.AuthSuccess",
32 value,
33 kSuccessRatioHistogramMaxValue);
36 // OAuth2 authorization token retrieval request.
37 class AuthRequest : public OAuth2TokenService::Consumer {
38 public:
39 AuthRequest(OAuth2TokenService* oauth2_token_service,
40 const std::string& account_id,
41 net::URLRequestContextGetter* url_request_context_getter,
42 const AuthStatusCallback& callback,
43 const std::vector<std::string>& scopes);
44 ~AuthRequest() override;
46 private:
47 // Overridden from OAuth2TokenService::Consumer:
48 void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
49 const std::string& access_token,
50 const base::Time& expiration_time) override;
51 void OnGetTokenFailure(const OAuth2TokenService::Request* request,
52 const GoogleServiceAuthError& error) override;
54 AuthStatusCallback callback_;
55 scoped_ptr<OAuth2TokenService::Request> request_;
56 base::ThreadChecker thread_checker_;
58 DISALLOW_COPY_AND_ASSIGN(AuthRequest);
61 AuthRequest::AuthRequest(
62 OAuth2TokenService* oauth2_token_service,
63 const std::string& account_id,
64 net::URLRequestContextGetter* url_request_context_getter,
65 const AuthStatusCallback& callback,
66 const std::vector<std::string>& scopes)
67 : OAuth2TokenService::Consumer("auth_service"),
68 callback_(callback) {
69 DCHECK(!callback_.is_null());
70 request_ = oauth2_token_service->
71 StartRequestWithContext(
72 account_id,
73 url_request_context_getter,
74 OAuth2TokenService::ScopeSet(scopes.begin(), scopes.end()),
75 this);
78 AuthRequest::~AuthRequest() {}
80 // Callback for OAuth2AccessTokenFetcher on success. |access_token| is the token
81 // used to start fetching user data.
82 void AuthRequest::OnGetTokenSuccess(const OAuth2TokenService::Request* request,
83 const std::string& access_token,
84 const base::Time& expiration_time) {
85 DCHECK(thread_checker_.CalledOnValidThread());
87 RecordAuthResultHistogram(kSuccessRatioHistogramSuccess);
88 callback_.Run(HTTP_SUCCESS, access_token);
89 delete this;
92 // Callback for OAuth2AccessTokenFetcher on failure.
93 void AuthRequest::OnGetTokenFailure(const OAuth2TokenService::Request* request,
94 const GoogleServiceAuthError& error) {
95 DCHECK(thread_checker_.CalledOnValidThread());
97 LOG(WARNING) << "AuthRequest: token request using refresh token failed: "
98 << error.ToString();
100 // There are many ways to fail, but if the failure is due to connection,
101 // it's likely that the device is off-line. We treat the error differently
102 // so that the file manager works while off-line.
103 if (error.state() == GoogleServiceAuthError::CONNECTION_FAILED) {
104 RecordAuthResultHistogram(kSuccessRatioHistogramNoConnection);
105 callback_.Run(DRIVE_NO_CONNECTION, std::string());
106 } else if (error.state() == GoogleServiceAuthError::SERVICE_UNAVAILABLE) {
107 RecordAuthResultHistogram(kSuccessRatioHistogramTemporaryFailure);
108 callback_.Run(HTTP_FORBIDDEN, std::string());
109 } else {
110 // Permanent auth error.
111 RecordAuthResultHistogram(kSuccessRatioHistogramFailure);
112 callback_.Run(HTTP_UNAUTHORIZED, std::string());
114 delete this;
117 } // namespace
119 AuthService::AuthService(
120 OAuth2TokenService* oauth2_token_service,
121 const std::string& account_id,
122 net::URLRequestContextGetter* url_request_context_getter,
123 const std::vector<std::string>& scopes)
124 : oauth2_token_service_(oauth2_token_service),
125 account_id_(account_id),
126 url_request_context_getter_(url_request_context_getter),
127 scopes_(scopes),
128 weak_ptr_factory_(this) {
129 DCHECK(oauth2_token_service);
131 // Get OAuth2 refresh token (if we have any) and register for its updates.
132 oauth2_token_service_->AddObserver(this);
133 has_refresh_token_ = oauth2_token_service_->RefreshTokenIsAvailable(
134 account_id_);
137 AuthService::~AuthService() {
138 oauth2_token_service_->RemoveObserver(this);
141 void AuthService::StartAuthentication(const AuthStatusCallback& callback) {
142 DCHECK(thread_checker_.CalledOnValidThread());
144 if (HasAccessToken()) {
145 // We already have access token. Give it back to the caller asynchronously.
146 base::MessageLoop::current()->PostTask(
147 FROM_HERE, base::Bind(callback, HTTP_SUCCESS, access_token_));
148 } else if (HasRefreshToken()) {
149 // We have refresh token, let's get an access token.
150 new AuthRequest(oauth2_token_service_,
151 account_id_,
152 url_request_context_getter_.get(),
153 base::Bind(&AuthService::OnAuthCompleted,
154 weak_ptr_factory_.GetWeakPtr(),
155 callback),
156 scopes_);
157 } else {
158 base::MessageLoop::current()->PostTask(
159 FROM_HERE, base::Bind(callback, DRIVE_NOT_READY, std::string()));
163 bool AuthService::HasAccessToken() const {
164 return !access_token_.empty();
167 bool AuthService::HasRefreshToken() const {
168 return has_refresh_token_;
171 const std::string& AuthService::access_token() const {
172 return access_token_;
175 void AuthService::ClearAccessToken() {
176 access_token_.clear();
179 void AuthService::ClearRefreshToken() {
180 OnHandleRefreshToken(false);
183 void AuthService::OnAuthCompleted(const AuthStatusCallback& callback,
184 DriveApiErrorCode error,
185 const std::string& access_token) {
186 DCHECK(thread_checker_.CalledOnValidThread());
187 DCHECK(!callback.is_null());
189 if (error == HTTP_SUCCESS) {
190 access_token_ = access_token;
191 } else if (error == HTTP_UNAUTHORIZED) {
192 // Refreshing access token using the refresh token is failed with 401 error
193 // (HTTP_UNAUTHORIZED). This means the current refresh token is invalid for
194 // Drive, hence we clear the refresh token here to make HasRefreshToken()
195 // false, thus the invalidness is clearly observable.
196 // This is not for triggering refetch of the refresh token. UI should
197 // show some message to encourage user to log-off and log-in again in order
198 // to fetch new valid refresh token.
199 ClearRefreshToken();
202 callback.Run(error, access_token);
205 void AuthService::AddObserver(AuthServiceObserver* observer) {
206 observers_.AddObserver(observer);
209 void AuthService::RemoveObserver(AuthServiceObserver* observer) {
210 observers_.RemoveObserver(observer);
213 void AuthService::OnRefreshTokenAvailable(const std::string& account_id) {
214 if (account_id == account_id_)
215 OnHandleRefreshToken(true);
218 void AuthService::OnRefreshTokenRevoked(const std::string& account_id) {
219 if (account_id == account_id_)
220 OnHandleRefreshToken(false);
223 void AuthService::OnHandleRefreshToken(bool has_refresh_token) {
224 access_token_.clear();
225 has_refresh_token_ = has_refresh_token;
227 FOR_EACH_OBSERVER(AuthServiceObserver,
228 observers_,
229 OnOAuth2RefreshTokenChanged());
232 } // namespace google_apis