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