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