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.
5 #ifndef CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_
6 #define CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_
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"
29 class GoogleServiceAuthError;
30 class MockGetAuthTokenFunction;
36 namespace extensions {
38 class GetAuthTokenFunctionTest;
39 class MockGetAuthTokenFunction;
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
55 class IdentityTokenCacheValue {
57 IdentityTokenCacheValue();
58 explicit IdentityTokenCacheValue(const IssueAdviceInfo& issue_advice);
59 IdentityTokenCacheValue(const std::string& token,
60 base::TimeDelta time_to_live);
61 ~IdentityTokenCacheValue();
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,
71 CacheValueStatus status() const;
72 const IssueAdviceInfo& issue_advice() const;
73 const std::string& token() const;
74 const base::Time& expiration_time() const;
77 bool is_expired() const;
79 CacheValueStatus status_;
80 IssueAdviceInfo issue_advice_;
82 base::Time expiration_time_;
85 class IdentityAPI : public BrowserContextKeyedAPI,
86 public AccountTracker::Observer {
88 typedef std::map<ExtensionTokenKey, IdentityTokenCacheValue> CachedTokens;
90 class ShutdownObserver {
92 virtual void OnShutdown() = 0;
95 explicit IdentityAPI(content::BrowserContext* context);
96 virtual ~IdentityAPI();
98 // Request serialization queue for getAuthToken.
99 IdentityMintRequestQueue* mint_queue();
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);
109 const CachedTokens& GetAllCachedTokens();
111 void ReportAuthError(const GoogleServiceAuthError& error);
112 GoogleServiceAuthError GetAuthStatusForTest() const;
114 // BrowserContextKeyedAPI implementation.
115 virtual void Shutdown() OVERRIDE;
116 static BrowserContextKeyedAPIFactory<IdentityAPI>* GetFactoryInstance();
118 // AccountTracker::Observer implementation:
119 virtual void OnAccountAdded(const AccountIds& ids) OVERRIDE;
120 virtual void OnAccountRemoved(const AccountIds& ids) OVERRIDE;
121 virtual void OnAccountSignInChanged(const AccountIds& ids,
122 bool is_signed_in) OVERRIDE;
124 void AddShutdownObserver(ShutdownObserver* observer);
125 void RemoveShutdownObserver(ShutdownObserver* observer);
128 friend class BrowserContextKeyedAPIFactory<IdentityAPI>;
130 // BrowserContextKeyedAPI implementation.
131 static const char* service_name() { return "IdentityAPI"; }
132 static const bool kServiceIsNULLWhileTesting = true;
134 content::BrowserContext* browser_context_;
135 IdentityMintRequestQueue mint_queue_;
136 CachedTokens token_cache_;
137 AccountTracker account_tracker_;
138 ObserverList<ShutdownObserver> shutdown_observer_list_;
142 void BrowserContextKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies();
144 // identity.getAuthToken fetches an OAuth 2 function for the
145 // caller. The request has three sub-flows: non-interactive,
146 // interactive, and sign-in.
148 // In the non-interactive flow, getAuthToken requests a token from
149 // GAIA. GAIA may respond with a token, an error, or "consent
150 // required". In the consent required cases, getAuthToken proceeds to
151 // the second, interactive phase.
153 // The interactive flow presents a scope approval dialog to the
154 // user. If the user approves the request, a grant will be recorded on
155 // the server, and an access token will be returned to the caller.
157 // In some cases we need to display a sign-in dialog. Normally the
158 // profile will be signed in already, but if it turns out we need a
159 // new login token, there is a sign-in flow. If that flow completes
160 // successfully, getAuthToken proceeds to the non-interactive flow.
161 class IdentityGetAuthTokenFunction : public ChromeAsyncExtensionFunction,
162 public GaiaWebAuthFlow::Delegate,
163 public IdentityMintRequestQueue::Request,
164 public OAuth2MintTokenFlow::Delegate,
165 public IdentitySigninFlow::Delegate,
166 public OAuth2TokenService::Consumer,
167 public IdentityAPI::ShutdownObserver {
169 DECLARE_EXTENSION_FUNCTION("identity.getAuthToken",
170 EXPERIMENTAL_IDENTITY_GETAUTHTOKEN);
172 IdentityGetAuthTokenFunction();
175 virtual ~IdentityGetAuthTokenFunction();
178 FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest,
179 ComponentWithChromeClientId);
180 FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest,
181 ComponentWithNormalClientId);
182 FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest, InteractiveQueueShutdown);
183 FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest, NoninteractiveShutdown);
184 friend class MockGetAuthTokenFunction;
186 // ExtensionFunction:
187 virtual bool RunAsync() OVERRIDE;
189 // Helpers to report async function results to the caller.
190 void StartAsyncRun();
191 void CompleteAsyncRun(bool success);
192 void CompleteFunctionWithResult(const std::string& access_token);
193 void CompleteFunctionWithError(const std::string& error);
195 // Initiate/complete the sub-flows.
196 void StartSigninFlow();
197 void StartMintTokenFlow(IdentityMintRequestQueue::MintType type);
198 void CompleteMintTokenFlow();
200 // IdentityMintRequestQueue::Request implementation:
201 virtual void StartMintToken(IdentityMintRequestQueue::MintType type) OVERRIDE;
203 // OAuth2MintTokenFlow::Delegate implementation:
204 virtual void OnMintTokenSuccess(const std::string& access_token,
205 int time_to_live) OVERRIDE;
206 virtual void OnMintTokenFailure(
207 const GoogleServiceAuthError& error) OVERRIDE;
208 virtual void OnIssueAdviceSuccess(
209 const IssueAdviceInfo& issue_advice) OVERRIDE;
211 // IdentitySigninFlow::Delegate implementation:
212 virtual void SigninSuccess() OVERRIDE;
213 virtual void SigninFailed() OVERRIDE;
215 // GaiaWebAuthFlow::Delegate implementation:
216 virtual void OnGaiaFlowFailure(GaiaWebAuthFlow::Failure failure,
217 GoogleServiceAuthError service_error,
218 const std::string& oauth_error) OVERRIDE;
219 virtual void OnGaiaFlowCompleted(const std::string& access_token,
220 const std::string& expiration) OVERRIDE;
222 // OAuth2TokenService::Consumer implementation:
223 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request,
224 const std::string& access_token,
225 const base::Time& expiration_time) OVERRIDE;
226 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request,
227 const GoogleServiceAuthError& error) OVERRIDE;
229 // IdentityAPI::ShutdownObserver implementation:
230 virtual void OnShutdown() OVERRIDE;
232 // Starts a login access token request.
233 virtual void StartLoginAccessTokenRequest();
235 #if defined(OS_CHROMEOS)
236 // Starts a login access token request for device robot account. This method
237 // will be called only in enterprise kiosk mode in ChromeOS.
238 virtual void StartDeviceLoginAccessTokenRequest();
241 // Starts a mint token request to GAIA.
242 void StartGaiaRequest(const std::string& login_access_token);
244 // Methods for invoking UI. Overridable for testing.
245 virtual void ShowLoginPopup();
246 virtual void ShowOAuthApprovalDialog(const IssueAdviceInfo& issue_advice);
247 // Caller owns the returned instance.
248 virtual OAuth2MintTokenFlow* CreateMintTokenFlow(
249 const std::string& login_access_token);
251 // Checks if there is a master login token to mint tokens for the extension.
252 virtual bool HasLoginToken() const;
254 // Maps OAuth2 protocol errors to an error message returned to the
255 // developer in chrome.runtime.lastError.
256 std::string MapOAuth2ErrorToDescription(const std::string& error);
258 std::string GetOAuth2ClientId() const;
260 bool should_prompt_for_scopes_;
261 IdentityMintRequestQueue::MintType mint_token_flow_type_;
262 scoped_ptr<OAuth2MintTokenFlow> mint_token_flow_;
263 OAuth2MintTokenFlow::Mode gaia_mint_token_mode_;
264 bool should_prompt_for_signin_;
266 scoped_ptr<ExtensionTokenKey> token_key_;
267 std::string oauth2_client_id_;
268 // When launched in interactive mode, and if there is no existing grant,
269 // a permissions prompt will be popped up to the user.
270 IssueAdviceInfo issue_advice_;
271 scoped_ptr<GaiaWebAuthFlow> gaia_web_auth_flow_;
272 scoped_ptr<IdentitySigninFlow> signin_flow_;
273 scoped_ptr<OAuth2TokenService::Request> login_token_request_;
276 class IdentityRemoveCachedAuthTokenFunction
277 : public ChromeSyncExtensionFunction {
279 DECLARE_EXTENSION_FUNCTION("identity.removeCachedAuthToken",
280 EXPERIMENTAL_IDENTITY_REMOVECACHEDAUTHTOKEN)
281 IdentityRemoveCachedAuthTokenFunction();
284 virtual ~IdentityRemoveCachedAuthTokenFunction();
286 // SyncExtensionFunction implementation:
287 virtual bool RunSync() OVERRIDE;
290 class IdentityLaunchWebAuthFlowFunction : public ChromeAsyncExtensionFunction,
291 public WebAuthFlow::Delegate {
293 DECLARE_EXTENSION_FUNCTION("identity.launchWebAuthFlow",
294 EXPERIMENTAL_IDENTITY_LAUNCHWEBAUTHFLOW);
296 IdentityLaunchWebAuthFlowFunction();
298 // Tests may override extension_id.
299 void InitFinalRedirectURLPrefixForTest(const std::string& extension_id);
302 virtual ~IdentityLaunchWebAuthFlowFunction();
303 virtual bool RunAsync() OVERRIDE;
305 // WebAuthFlow::Delegate implementation.
306 virtual void OnAuthFlowFailure(WebAuthFlow::Failure failure) OVERRIDE;
307 virtual void OnAuthFlowURLChange(const GURL& redirect_url) OVERRIDE;
308 virtual void OnAuthFlowTitleChange(const std::string& title) OVERRIDE {}
310 // Helper to initialize final URL prefix.
311 void InitFinalRedirectURLPrefix(const std::string& extension_id);
313 scoped_ptr<WebAuthFlow> auth_flow_;
314 GURL final_url_prefix_;
317 } // namespace extensions
319 #endif // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_