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)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef GOOGLE_APIS_GAIA_OAUTH2_API_CALL_FLOW_H_
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define GOOGLE_APIS_GAIA_OAUTH2_API_CALL_FLOW_H_
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
10a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "base/gtest_prod_util.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/oauth2_access_token_consumer.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "google_apis/gaia/oauth2_access_token_fetcher.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/url_request/url_fetcher_delegate.h"
15a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "url/gurl.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class GoogleServiceAuthError;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OAuth2MintTokenFlowTest;
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net {
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class URLFetcher;
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class URLRequestContextGetter;
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Base class for all classes that implement a flow to call OAuth2
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// enabled APIs.
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Given a refresh token, an access token, and a list of scopes an OAuth2
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// enabled API is called in the following way:
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 1. Try the given access token to call the API.
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2. If that does not work, use the refresh token and scopes to generate
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    a new access token.
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3. Try the new access token to call the API.
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This class abstracts the basic steps and exposes template methods
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// for sub-classes to implement for API specific details.
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class OAuth2ApiCallFlow
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : public net::URLFetcherDelegate,
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      public OAuth2AccessTokenConsumer {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates an instance that works with the given data.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that |access_token| can be empty. In that case, the flow will skip
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the first step (of trying an existing access token).
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OAuth2ApiCallFlow(
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      net::URLRequestContextGetter* context,
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& refresh_token,
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::string& access_token,
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const std::vector<std::string>& scopes);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~OAuth2ApiCallFlow();
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Start the flow.
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Start();
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // OAuth2AccessTokenFetcher implementation.
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnGetTokenSuccess(const std::string& access_token,
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 const base::Time& expiration_time) OVERRIDE;
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnGetTokenFailure(const GoogleServiceAuthError& error) OVERRIDE;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // net::URLFetcherDelegate implementation.
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) protected:
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Template methods for sub-classes.
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Methods to help create HTTP request.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual GURL CreateApiCallUrl() = 0;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual std::string CreateApiCallBody() = 0;
696e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  virtual std::string CreateApiCallBodyContentType();
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sub-classes can expose an appropriate observer interface by implementing
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // these template methods.
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called when the API call finished successfully.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ProcessApiCallSuccess(const net::URLFetcher* source) = 0;
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called when the API call failed.
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ProcessApiCallFailure(const net::URLFetcher* source) = 0;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Called when a new access token is generated.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ProcessNewAccessToken(const std::string& access_token) = 0;
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void ProcessMintAccessTokenFailure(
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      const GoogleServiceAuthError& error) = 0;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  enum State {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    INITIAL,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    API_CALL_STARTED,
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    API_CALL_DONE,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MINT_ACCESS_TOKEN_STARTED,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    MINT_ACCESS_TOKEN_DONE,
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ERROR_STATE
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class OAuth2ApiCallFlowTest;
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  FRIEND_TEST_ALL_PREFIXES(OAuth2ApiCallFlowTest, CreateURLFetcher);
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper to create an instance of access token fetcher.
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Caller owns the returned instance.
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that this is virtual since it is mocked during unit testing.
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual OAuth2AccessTokenFetcher* CreateAccessTokenFetcher();
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Creates an instance of URLFetcher that does not send or save cookies.
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Template method CreateApiCallUrl is used to get the URL.
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Template method CreateApiCallBody is used to get the body.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The URLFether's method will be GET if body is empty, POST otherwise.
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Caller owns the returned instance.
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Note that this is virtual since it is mocked during unit testing.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual net::URLFetcher* CreateURLFetcher();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Helper methods to implement the state machine for the flow.
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void BeginApiCall();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void EndApiCall(const net::URLFetcher* source);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void BeginMintAccessToken();
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void EndMintAccessToken(const GoogleServiceAuthError* error);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  net::URLRequestContextGetter* context_;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string refresh_token_;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::string access_token_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::vector<std::string> scopes_;
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  State state_;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Whether we have already tried minting an access token once.
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool tried_mint_access_token_;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<net::URLFetcher> url_fetcher_;
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<OAuth2AccessTokenFetcher> oauth2_access_token_fetcher_;
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(OAuth2ApiCallFlow);
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // GOOGLE_APIS_GAIA_OAUTH2_API_CALL_FLOW_H_
130