1 // Copyright 2014 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
5 #include "google_apis/gaia/oauth2_token_service_request.h"
6
7 #include "base/bind.h"
8 #include "base/memory/ref_counted.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/single_thread_task_runner.h"
11 #include "base/thread_task_runner_handle.h"
12 #include "google_apis/gaia/google_service_auth_error.h"
13 #include "google_apis/gaia/oauth2_access_token_consumer.h"
14
TokenServiceProvider()15 OAuth2TokenServiceRequest::TokenServiceProvider::TokenServiceProvider() {
16 }
17
~TokenServiceProvider()18 OAuth2TokenServiceRequest::TokenServiceProvider::~TokenServiceProvider() {
19 }
20
21 // Core serves as the base class for OAuth2TokenService operations. Each
22 // operation should be modeled as a derived type.
23 //
24 // Core is used like this:
25 //
26 // 1. Constructed on owner thread.
27 //
28 // 2. Start() is called on owner thread, which calls StartOnTokenServiceThread()
29 // on token service thread.
30 //
31 // 3. Request is executed.
32 //
33 // 4. Stop() is called on owner thread, which calls StopOnTokenServiceThread()
34 // on token service thread.
35 //
36 // 5. Core is destroyed on owner thread.
37 class OAuth2TokenServiceRequest::Core
38 : public base::NonThreadSafe,
39 public base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core> {
40 public:
41 // Note the thread where an instance of Core is constructed is referred to as
42 // the "owner thread" here.
43 Core(OAuth2TokenServiceRequest* owner, TokenServiceProvider* provider);
44
45 // Starts the core. Must be called on the owner thread.
46 void Start();
47
48 // Stops the core. Must be called on the owner thread.
49 void Stop();
50
51 // Returns true if this object has been stopped. Must be called on the owner
52 // thread.
53 bool IsStopped() const;
54
55 protected:
56 // Core must be destroyed on the owner thread. If data members must be
57 // cleaned up or destroyed on the token service thread, do so in the
58 // StopOnTokenServiceThread method.
59 virtual ~Core();
60
61 // Called on the token service thread.
62 virtual void StartOnTokenServiceThread() = 0;
63
64 // Called on the token service thread.
65 virtual void StopOnTokenServiceThread() = 0;
66
67 base::SingleThreadTaskRunner* token_service_task_runner();
68 OAuth2TokenService* token_service();
69 OAuth2TokenServiceRequest* owner();
70
71 private:
72 friend class base::RefCountedThreadSafe<OAuth2TokenServiceRequest::Core>;
73
74 void DoNothing();
75
76 scoped_refptr<base::SingleThreadTaskRunner> token_service_task_runner_;
77 OAuth2TokenServiceRequest* owner_;
78 TokenServiceProvider* provider_;
79 DISALLOW_COPY_AND_ASSIGN(Core);
80 };
81
Core(OAuth2TokenServiceRequest * owner,TokenServiceProvider * provider)82 OAuth2TokenServiceRequest::Core::Core(OAuth2TokenServiceRequest* owner,
83 TokenServiceProvider* provider)
84 : owner_(owner), provider_(provider) {
85 DCHECK(owner_);
86 DCHECK(provider_);
87 token_service_task_runner_ = provider_->GetTokenServiceTaskRunner();
88 DCHECK(token_service_task_runner_);
89 }
90
~Core()91 OAuth2TokenServiceRequest::Core::~Core() {
92 }
93
Start()94 void OAuth2TokenServiceRequest::Core::Start() {
95 DCHECK(CalledOnValidThread());
96 token_service_task_runner_->PostTask(
97 FROM_HERE,
98 base::Bind(&OAuth2TokenServiceRequest::Core::StartOnTokenServiceThread,
99 this));
100 }
101
Stop()102 void OAuth2TokenServiceRequest::Core::Stop() {
103 DCHECK(CalledOnValidThread());
104 DCHECK(!IsStopped());
105
106 // Detaches |owner_| from this instance so |owner_| will be called back only
107 // if |Stop()| has never been called.
108 owner_ = NULL;
109
110 // We are stopping and will likely be destroyed soon. Use a reply closure
111 // (DoNothing) to retain "this" and ensure we are destroyed in the owner
112 // thread, not the task runner thread. PostTaskAndReply guarantees that the
113 // reply closure will execute after StopOnTokenServiceThread has completed.
114 token_service_task_runner_->PostTaskAndReply(
115 FROM_HERE,
116 base::Bind(&OAuth2TokenServiceRequest::Core::StopOnTokenServiceThread,
117 this),
118 base::Bind(&OAuth2TokenServiceRequest::Core::DoNothing, this));
119 }
120
IsStopped() const121 bool OAuth2TokenServiceRequest::Core::IsStopped() const {
122 DCHECK(CalledOnValidThread());
123 return owner_ == NULL;
124 }
125
126 base::SingleThreadTaskRunner*
token_service_task_runner()127 OAuth2TokenServiceRequest::Core::token_service_task_runner() {
128 return token_service_task_runner_;
129 }
130
token_service()131 OAuth2TokenService* OAuth2TokenServiceRequest::Core::token_service() {
132 DCHECK(token_service_task_runner_->BelongsToCurrentThread());
133 return provider_->GetTokenService();
134 }
135
owner()136 OAuth2TokenServiceRequest* OAuth2TokenServiceRequest::Core::owner() {
137 DCHECK(CalledOnValidThread());
138 return owner_;
139 }
140
DoNothing()141 void OAuth2TokenServiceRequest::Core::DoNothing() {
142 DCHECK(CalledOnValidThread());
143 }
144
145 namespace {
146
147 // An implementation of Core for getting an access token.
148 class RequestCore : public OAuth2TokenServiceRequest::Core,
149 public OAuth2TokenService::Consumer {
150 public:
151 RequestCore(OAuth2TokenServiceRequest* owner,
152 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
153 OAuth2TokenService::Consumer* consumer,
154 const std::string& account_id,
155 const OAuth2TokenService::ScopeSet& scopes);
156
157 // OAuth2TokenService::Consumer. Must be called on the token service thread.
158 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
159 const std::string& access_token,
160 const base::Time& expiration_time) OVERRIDE;
161 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
162 const GoogleServiceAuthError& error) OVERRIDE;
163
164 private:
165 friend class base::RefCountedThreadSafe<RequestCore>;
166
167 // Must be destroyed on the owner thread.
168 virtual ~RequestCore();
169
170 // Core implementation.
171 virtual void StartOnTokenServiceThread() OVERRIDE;
172 virtual void StopOnTokenServiceThread() OVERRIDE;
173
174 void InformOwnerOnGetTokenSuccess(std::string access_token,
175 base::Time expiration_time);
176 void InformOwnerOnGetTokenFailure(GoogleServiceAuthError error);
177
178 scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner_;
179 OAuth2TokenService::Consumer* const consumer_;
180 std::string account_id_;
181 OAuth2TokenService::ScopeSet scopes_;
182
183 // OAuth2TokenService request for fetching OAuth2 access token; it should be
184 // created, reset and accessed only on the token service thread.
185 scoped_ptr<OAuth2TokenService::Request> request_;
186
187 DISALLOW_COPY_AND_ASSIGN(RequestCore);
188 };
189
RequestCore(OAuth2TokenServiceRequest * owner,OAuth2TokenServiceRequest::TokenServiceProvider * provider,OAuth2TokenService::Consumer * consumer,const std::string & account_id,const OAuth2TokenService::ScopeSet & scopes)190 RequestCore::RequestCore(
191 OAuth2TokenServiceRequest* owner,
192 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
193 OAuth2TokenService::Consumer* consumer,
194 const std::string& account_id,
195 const OAuth2TokenService::ScopeSet& scopes)
196 : OAuth2TokenServiceRequest::Core(owner, provider),
197 OAuth2TokenService::Consumer("oauth2_token_service"),
198 owner_task_runner_(base::ThreadTaskRunnerHandle::Get()),
199 consumer_(consumer),
200 account_id_(account_id),
201 scopes_(scopes) {
202 DCHECK(consumer_);
203 DCHECK(!account_id_.empty());
204 DCHECK(!scopes_.empty());
205 }
206
~RequestCore()207 RequestCore::~RequestCore() {
208 }
209
StartOnTokenServiceThread()210 void RequestCore::StartOnTokenServiceThread() {
211 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
212 request_ = token_service()->StartRequest(account_id_, scopes_, this).Pass();
213 }
214
StopOnTokenServiceThread()215 void RequestCore::StopOnTokenServiceThread() {
216 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
217 request_.reset();
218 }
219
OnGetTokenSuccess(const OAuth2TokenService::Request * request,const std::string & access_token,const base::Time & expiration_time)220 void RequestCore::OnGetTokenSuccess(const OAuth2TokenService::Request* request,
221 const std::string& access_token,
222 const base::Time& expiration_time) {
223 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
224 DCHECK_EQ(request_.get(), request);
225 owner_task_runner_->PostTask(
226 FROM_HERE,
227 base::Bind(&RequestCore::InformOwnerOnGetTokenSuccess,
228 this,
229 access_token,
230 expiration_time));
231 request_.reset();
232 }
233
OnGetTokenFailure(const OAuth2TokenService::Request * request,const GoogleServiceAuthError & error)234 void RequestCore::OnGetTokenFailure(const OAuth2TokenService::Request* request,
235 const GoogleServiceAuthError& error) {
236 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
237 DCHECK_EQ(request_.get(), request);
238 owner_task_runner_->PostTask(
239 FROM_HERE,
240 base::Bind(&RequestCore::InformOwnerOnGetTokenFailure, this, error));
241 request_.reset();
242 }
243
InformOwnerOnGetTokenSuccess(std::string access_token,base::Time expiration_time)244 void RequestCore::InformOwnerOnGetTokenSuccess(std::string access_token,
245 base::Time expiration_time) {
246 DCHECK(CalledOnValidThread());
247 if (!IsStopped()) {
248 consumer_->OnGetTokenSuccess(owner(), access_token, expiration_time);
249 }
250 }
251
InformOwnerOnGetTokenFailure(GoogleServiceAuthError error)252 void RequestCore::InformOwnerOnGetTokenFailure(GoogleServiceAuthError error) {
253 DCHECK(CalledOnValidThread());
254 if (!IsStopped()) {
255 consumer_->OnGetTokenFailure(owner(), error);
256 }
257 }
258
259 // An implementation of Core for invalidating an access token.
260 class InvalidateCore : public OAuth2TokenServiceRequest::Core {
261 public:
262 InvalidateCore(OAuth2TokenServiceRequest* owner,
263 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
264 const std::string& access_token,
265 const std::string& account_id,
266 const OAuth2TokenService::ScopeSet& scopes);
267
268 private:
269 friend class base::RefCountedThreadSafe<InvalidateCore>;
270
271 // Must be destroyed on the owner thread.
272 virtual ~InvalidateCore();
273
274 // Core implementation.
275 virtual void StartOnTokenServiceThread() OVERRIDE;
276 virtual void StopOnTokenServiceThread() OVERRIDE;
277
278 std::string access_token_;
279 std::string account_id_;
280 OAuth2TokenService::ScopeSet scopes_;
281
282 DISALLOW_COPY_AND_ASSIGN(InvalidateCore);
283 };
284
InvalidateCore(OAuth2TokenServiceRequest * owner,OAuth2TokenServiceRequest::TokenServiceProvider * provider,const std::string & access_token,const std::string & account_id,const OAuth2TokenService::ScopeSet & scopes)285 InvalidateCore::InvalidateCore(
286 OAuth2TokenServiceRequest* owner,
287 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
288 const std::string& access_token,
289 const std::string& account_id,
290 const OAuth2TokenService::ScopeSet& scopes)
291 : OAuth2TokenServiceRequest::Core(owner, provider),
292 access_token_(access_token),
293 account_id_(account_id),
294 scopes_(scopes) {
295 DCHECK(!access_token_.empty());
296 DCHECK(!account_id_.empty());
297 DCHECK(!scopes.empty());
298 }
299
~InvalidateCore()300 InvalidateCore::~InvalidateCore() {
301 }
302
StartOnTokenServiceThread()303 void InvalidateCore::StartOnTokenServiceThread() {
304 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
305 token_service()->InvalidateToken(account_id_, scopes_, access_token_);
306 }
307
StopOnTokenServiceThread()308 void InvalidateCore::StopOnTokenServiceThread() {
309 DCHECK(token_service_task_runner()->BelongsToCurrentThread());
310 // Nothing to do.
311 }
312
313 } // namespace
314
315 // static
CreateAndStart(TokenServiceProvider * provider,const std::string & account_id,const OAuth2TokenService::ScopeSet & scopes,OAuth2TokenService::Consumer * consumer)316 scoped_ptr<OAuth2TokenServiceRequest> OAuth2TokenServiceRequest::CreateAndStart(
317 TokenServiceProvider* provider,
318 const std::string& account_id,
319 const OAuth2TokenService::ScopeSet& scopes,
320 OAuth2TokenService::Consumer* consumer) {
321 scoped_ptr<OAuth2TokenServiceRequest> request(
322 new OAuth2TokenServiceRequest(account_id));
323 scoped_refptr<Core> core(
324 new RequestCore(request.get(), provider, consumer, account_id, scopes));
325 request->StartWithCore(core);
326 return request.Pass();
327 }
328
329 // static
InvalidateToken(OAuth2TokenServiceRequest::TokenServiceProvider * provider,const std::string & account_id,const OAuth2TokenService::ScopeSet & scopes,const std::string & access_token)330 void OAuth2TokenServiceRequest::InvalidateToken(
331 OAuth2TokenServiceRequest::TokenServiceProvider* provider,
332 const std::string& account_id,
333 const OAuth2TokenService::ScopeSet& scopes,
334 const std::string& access_token) {
335 scoped_ptr<OAuth2TokenServiceRequest> request(
336 new OAuth2TokenServiceRequest(account_id));
337 scoped_refptr<Core> core(new InvalidateCore(
338 request.get(), provider, access_token, account_id, scopes));
339 request->StartWithCore(core);
340 }
341
~OAuth2TokenServiceRequest()342 OAuth2TokenServiceRequest::~OAuth2TokenServiceRequest() {
343 core_->Stop();
344 }
345
GetAccountId() const346 std::string OAuth2TokenServiceRequest::GetAccountId() const {
347 return account_id_;
348 }
349
OAuth2TokenServiceRequest(const std::string & account_id)350 OAuth2TokenServiceRequest::OAuth2TokenServiceRequest(
351 const std::string& account_id)
352 : account_id_(account_id) {
353 DCHECK(!account_id_.empty());
354 }
355
StartWithCore(const scoped_refptr<Core> & core)356 void OAuth2TokenServiceRequest::StartWithCore(const scoped_refptr<Core>& core) {
357 DCHECK(core);
358 core_ = core;
359 core_->Start();
360 }
361