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