Home | History | Annotate | Download | only in identity
      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 
      5 #ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_
      6 #define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_
      7 
      8 #include <map>
      9 #include <set>
     10 #include <string>
     11 #include <utility>
     12 #include <vector>
     13 
     14 #include "base/memory/ref_counted.h"
     15 #include "base/memory/weak_ptr.h"
     16 #include "chrome/browser/extensions/api/identity/gaia_web_auth_flow.h"
     17 #include "chrome/browser/extensions/api/identity/identity_mint_queue.h"
     18 #include "chrome/browser/extensions/api/identity/identity_signin_flow.h"
     19 #include "chrome/browser/extensions/api/identity/web_auth_flow.h"
     20 #include "chrome/browser/extensions/api/profile_keyed_api_factory.h"
     21 #include "chrome/browser/extensions/extension_function.h"
     22 #include "chrome/browser/signin/oauth2_token_service.h"
     23 #include "chrome/browser/signin/signin_global_error.h"
     24 #include "google_apis/gaia/oauth2_mint_token_flow.h"
     25 
     26 class GoogleServiceAuthError;
     27 class MockGetAuthTokenFunction;
     28 class Profile;
     29 
     30 namespace extensions {
     31 
     32 class GetAuthTokenFunctionTest;
     33 class MockGetAuthTokenFunction;
     34 
     35 namespace identity_constants {
     36 extern const char kInvalidClientId[];
     37 extern const char kInvalidScopes[];
     38 extern const char kAuthFailure[];
     39 extern const char kNoGrant[];
     40 extern const char kUserRejected[];
     41 extern const char kUserNotSignedIn[];
     42 extern const char kInteractionRequired[];
     43 extern const char kInvalidRedirect[];
     44 extern const char kOffTheRecord[];
     45 extern const char kPageLoadFailure[];
     46 }  // namespace identity_constants
     47 
     48 // identity.getAuthToken fetches an OAuth 2 function for the
     49 // caller. The request has three sub-flows: non-interactive,
     50 // interactive, and sign-in.
     51 //
     52 // In the non-interactive flow, getAuthToken requests a token from
     53 // GAIA. GAIA may respond with a token, an error, or "consent
     54 // required". In the consent required cases, getAuthToken proceeds to
     55 // the second, interactive phase.
     56 //
     57 // The interactive flow presents a scope approval dialog to the
     58 // user. If the user approves the request, a grant will be recorded on
     59 // the server, and an access token will be returned to the caller.
     60 //
     61 // In some cases we need to display a sign-in dialog. Normally the
     62 // profile will be signed in already, but if it turns out we need a
     63 // new login token, there is a sign-in flow. If that flow completes
     64 // successfully, getAuthToken proceeds to the non-interactive flow.
     65 class IdentityGetAuthTokenFunction : public AsyncExtensionFunction,
     66                                      public GaiaWebAuthFlow::Delegate,
     67                                      public IdentityMintRequestQueue::Request,
     68                                      public OAuth2MintTokenFlow::Delegate,
     69                                      public IdentitySigninFlow::Delegate,
     70                                      public OAuth2TokenService::Consumer {
     71  public:
     72   DECLARE_EXTENSION_FUNCTION("identity.getAuthToken",
     73                              EXPERIMENTAL_IDENTITY_GETAUTHTOKEN);
     74 
     75   IdentityGetAuthTokenFunction();
     76 
     77  protected:
     78   virtual ~IdentityGetAuthTokenFunction();
     79 
     80  private:
     81   FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest,
     82                            ComponentWithChromeClientId);
     83   FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest,
     84                            ComponentWithNormalClientId);
     85   friend class MockGetAuthTokenFunction;
     86 
     87   // ExtensionFunction:
     88   virtual bool RunImpl() OVERRIDE;
     89 
     90   // Helpers to report async function results to the caller.
     91   void CompleteFunctionWithResult(const std::string& access_token);
     92   void CompleteFunctionWithError(const std::string& error);
     93 
     94   // Initiate/complete the sub-flows.
     95   void StartSigninFlow();
     96   void StartMintTokenFlow(IdentityMintRequestQueue::MintType type);
     97   void CompleteMintTokenFlow();
     98 
     99   // IdentityMintRequestQueue::Request implementation:
    100   virtual void StartMintToken(IdentityMintRequestQueue::MintType type) OVERRIDE;
    101 
    102   // OAuth2MintTokenFlow::Delegate implementation:
    103   virtual void OnMintTokenSuccess(const std::string& access_token,
    104                                   int time_to_live) OVERRIDE;
    105   virtual void OnMintTokenFailure(
    106       const GoogleServiceAuthError& error) OVERRIDE;
    107   virtual void OnIssueAdviceSuccess(
    108       const IssueAdviceInfo& issue_advice) OVERRIDE;
    109 
    110   // IdentitySigninFlow::Delegate implementation:
    111   virtual void SigninSuccess() OVERRIDE;
    112   virtual void SigninFailed() OVERRIDE;
    113 
    114   // GaiaWebAuthFlow::Delegate implementation:
    115   virtual void OnGaiaFlowFailure(GaiaWebAuthFlow::Failure failure,
    116                                  GoogleServiceAuthError service_error,
    117                                  const std::string& oauth_error) OVERRIDE;
    118   virtual void OnGaiaFlowCompleted(const std::string& access_token,
    119                                    const std::string& expiration) OVERRIDE;
    120 
    121   // OAuth2TokenService::Consumer implementation:
    122   virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
    123                                  const std::string& access_token,
    124                                  const base::Time& expiration_time) OVERRIDE;
    125   virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
    126                                  const GoogleServiceAuthError& error) OVERRIDE;
    127 
    128   // Starts a login access token request.
    129   virtual void StartLoginAccessTokenRequest();
    130 
    131   // Starts a mint token request to GAIA.
    132   void StartGaiaRequest(const std::string& login_access_token);
    133 
    134   // Methods for invoking UI. Overridable for testing.
    135   virtual void ShowLoginPopup();
    136   virtual void ShowOAuthApprovalDialog(const IssueAdviceInfo& issue_advice);
    137   // Caller owns the returned instance.
    138   virtual OAuth2MintTokenFlow* CreateMintTokenFlow(
    139       const std::string& login_access_token);
    140 
    141   // Checks if there is a master login token to mint tokens for the extension.
    142   virtual bool HasLoginToken() const;
    143 
    144   // Maps OAuth2 protocol errors to an error message returned to the
    145   // developer in chrome.runtime.lastError.
    146   std::string MapOAuth2ErrorToDescription(const std::string& error);
    147 
    148   std::string GetOAuth2ClientId() const;
    149 
    150   bool should_prompt_for_scopes_;
    151   IdentityMintRequestQueue::MintType mint_token_flow_type_;
    152   scoped_ptr<OAuth2MintTokenFlow> mint_token_flow_;
    153   OAuth2MintTokenFlow::Mode gaia_mint_token_mode_;
    154   bool should_prompt_for_signin_;
    155 
    156   std::string oauth2_client_id_;
    157   // When launched in interactive mode, and if there is no existing grant,
    158   // a permissions prompt will be popped up to the user.
    159   IssueAdviceInfo issue_advice_;
    160   scoped_ptr<GaiaWebAuthFlow> gaia_web_auth_flow_;
    161   scoped_ptr<IdentitySigninFlow> signin_flow_;
    162   scoped_ptr<OAuth2TokenService::Request> device_token_request_;
    163   scoped_ptr<OAuth2TokenService::Request> login_token_request_;
    164 };
    165 
    166 class IdentityRemoveCachedAuthTokenFunction : public SyncExtensionFunction {
    167  public:
    168   DECLARE_EXTENSION_FUNCTION("identity.removeCachedAuthToken",
    169                              EXPERIMENTAL_IDENTITY_REMOVECACHEDAUTHTOKEN)
    170   IdentityRemoveCachedAuthTokenFunction();
    171 
    172  protected:
    173   virtual ~IdentityRemoveCachedAuthTokenFunction();
    174 
    175   // SyncExtensionFunction implementation:
    176   virtual bool RunImpl() OVERRIDE;
    177 };
    178 
    179 class IdentityLaunchWebAuthFlowFunction : public AsyncExtensionFunction,
    180                                           public WebAuthFlow::Delegate {
    181  public:
    182   DECLARE_EXTENSION_FUNCTION("identity.launchWebAuthFlow",
    183                              EXPERIMENTAL_IDENTITY_LAUNCHWEBAUTHFLOW);
    184 
    185   IdentityLaunchWebAuthFlowFunction();
    186 
    187   // Tests may override extension_id.
    188   void InitFinalRedirectURLPrefixForTest(const std::string& extension_id);
    189 
    190  private:
    191   virtual ~IdentityLaunchWebAuthFlowFunction();
    192   virtual bool RunImpl() OVERRIDE;
    193 
    194   // WebAuthFlow::Delegate implementation.
    195   virtual void OnAuthFlowFailure(WebAuthFlow::Failure failure) OVERRIDE;
    196   virtual void OnAuthFlowURLChange(const GURL& redirect_url) OVERRIDE;
    197   virtual void OnAuthFlowTitleChange(const std::string& title) OVERRIDE {}
    198 
    199   // Helper to initialize final URL prefix.
    200   void InitFinalRedirectURLPrefix(const std::string& extension_id);
    201 
    202   scoped_ptr<WebAuthFlow> auth_flow_;
    203   GURL final_url_prefix_;
    204 };
    205 
    206 class IdentityTokenCacheValue {
    207  public:
    208   IdentityTokenCacheValue();
    209   explicit IdentityTokenCacheValue(const IssueAdviceInfo& issue_advice);
    210   IdentityTokenCacheValue(const std::string& token,
    211                           base::TimeDelta time_to_live);
    212   ~IdentityTokenCacheValue();
    213 
    214   // Order of these entries is used to determine whether or not new
    215   // entries supercede older ones in SetCachedToken.
    216   enum CacheValueStatus {
    217     CACHE_STATUS_NOTFOUND,
    218     CACHE_STATUS_ADVICE,
    219     CACHE_STATUS_TOKEN
    220   };
    221 
    222   CacheValueStatus status() const;
    223   const IssueAdviceInfo& issue_advice() const;
    224   const std::string& token() const;
    225   const base::Time& expiration_time() const;
    226 
    227  private:
    228   bool is_expired() const;
    229 
    230   CacheValueStatus status_;
    231   IssueAdviceInfo issue_advice_;
    232   std::string token_;
    233   base::Time expiration_time_;
    234 };
    235 
    236 class IdentityAPI : public ProfileKeyedAPI,
    237                     public SigninGlobalError::AuthStatusProvider,
    238                     public OAuth2TokenService::Observer {
    239  public:
    240   struct TokenCacheKey {
    241     TokenCacheKey(const std::string& extension_id,
    242                   const std::set<std::string> scopes);
    243     ~TokenCacheKey();
    244     bool operator<(const TokenCacheKey& rhs) const;
    245     std::string extension_id;
    246     std::set<std::string> scopes;
    247   };
    248 
    249   typedef std::map<TokenCacheKey, IdentityTokenCacheValue> CachedTokens;
    250 
    251   explicit IdentityAPI(Profile* profile);
    252   virtual ~IdentityAPI();
    253   void Initialize();
    254 
    255   // Request serialization queue for getAuthToken.
    256   IdentityMintRequestQueue* mint_queue();
    257 
    258   // Token cache
    259   void SetCachedToken(const std::string& extension_id,
    260                       const std::vector<std::string> scopes,
    261                       const IdentityTokenCacheValue& token_data);
    262   void EraseCachedToken(const std::string& extension_id,
    263                         const std::string& token);
    264   void EraseAllCachedTokens();
    265   const IdentityTokenCacheValue& GetCachedToken(
    266       const std::string& extension_id, const std::vector<std::string> scopes);
    267 
    268   const CachedTokens& GetAllCachedTokens();
    269 
    270   void ReportAuthError(const GoogleServiceAuthError& error);
    271 
    272   // ProfileKeyedAPI implementation.
    273   virtual void Shutdown() OVERRIDE;
    274   static ProfileKeyedAPIFactory<IdentityAPI>* GetFactoryInstance();
    275 
    276   // AuthStatusProvider implementation.
    277   virtual GoogleServiceAuthError GetAuthStatus() const OVERRIDE;
    278 
    279   // OAuth2TokenService::Observer implementation:
    280   virtual void OnRefreshTokenAvailable(const std::string& account_id) OVERRIDE;
    281 
    282  private:
    283   friend class ProfileKeyedAPIFactory<IdentityAPI>;
    284 
    285   // ProfileKeyedAPI implementation.
    286   static const char* service_name() {
    287     return "IdentityAPI";
    288   }
    289   static const bool kServiceIsNULLWhileTesting = true;
    290 
    291   Profile* profile_;
    292   GoogleServiceAuthError error_;
    293   bool initialized_;
    294   IdentityMintRequestQueue mint_queue_;
    295   CachedTokens token_cache_;
    296 };
    297 
    298 template <>
    299 void ProfileKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies();
    300 
    301 }  // namespace extensions
    302 
    303 #endif  // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_
    304