identity_api.h revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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 29class GoogleServiceAuthError; 30class MockGetAuthTokenFunction; 31 32namespace content { 33class BrowserContext; 34} 35 36namespace extensions { 37 38class GetAuthTokenFunctionTest; 39class MockGetAuthTokenFunction; 40 41namespace identity_constants { 42extern const char kInvalidClientId[]; 43extern const char kInvalidScopes[]; 44extern const char kAuthFailure[]; 45extern const char kNoGrant[]; 46extern const char kUserRejected[]; 47extern const char kUserNotSignedIn[]; 48extern const char kInteractionRequired[]; 49extern const char kInvalidRedirect[]; 50extern const char kOffTheRecord[]; 51extern const char kPageLoadFailure[]; 52extern const char kCanceled[]; 53} // namespace identity_constants 54 55class 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 85class 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 114 // Global error reporting. 115 void ReportAuthError(const GoogleServiceAuthError& error); 116 GoogleServiceAuthError GetAuthStatusForTest() const; 117 118 // BrowserContextKeyedAPI implementation. 119 virtual void Shutdown() OVERRIDE; 120 static BrowserContextKeyedAPIFactory<IdentityAPI>* GetFactoryInstance(); 121 122 // AccountTracker::Observer implementation: 123 virtual void OnAccountAdded(const AccountIds& ids) OVERRIDE; 124 virtual void OnAccountRemoved(const AccountIds& ids) OVERRIDE; 125 virtual void OnAccountSignInChanged(const AccountIds& ids, 126 bool is_signed_in) OVERRIDE; 127 128 void AddShutdownObserver(ShutdownObserver* observer); 129 void RemoveShutdownObserver(ShutdownObserver* observer); 130 131 void SetAccountStateForTest(AccountIds ids, bool is_signed_in); 132 133 private: 134 friend class BrowserContextKeyedAPIFactory<IdentityAPI>; 135 136 // BrowserContextKeyedAPI implementation. 137 static const char* service_name() { return "IdentityAPI"; } 138 static const bool kServiceIsNULLWhileTesting = true; 139 140 content::BrowserContext* browser_context_; 141 IdentityMintRequestQueue mint_queue_; 142 CachedTokens token_cache_; 143 AccountTracker account_tracker_; 144 ObserverList<ShutdownObserver> shutdown_observer_list_; 145}; 146 147template <> 148void BrowserContextKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies(); 149 150class IdentityGetAccountsFunction : public ChromeUIThreadExtensionFunction { 151 public: 152 DECLARE_EXTENSION_FUNCTION("identity.getAccounts", 153 IDENTITY_GETACCOUNTS); 154 155 IdentityGetAccountsFunction(); 156 157 private: 158 virtual ~IdentityGetAccountsFunction(); 159 160 // UIThreadExtensionFunction implementation. 161 virtual ExtensionFunction::ResponseAction Run() OVERRIDE; 162}; 163 164// identity.getAuthToken fetches an OAuth 2 function for the 165// caller. The request has three sub-flows: non-interactive, 166// interactive, and sign-in. 167// 168// In the non-interactive flow, getAuthToken requests a token from 169// GAIA. GAIA may respond with a token, an error, or "consent 170// required". In the consent required cases, getAuthToken proceeds to 171// the second, interactive phase. 172// 173// The interactive flow presents a scope approval dialog to the 174// user. If the user approves the request, a grant will be recorded on 175// the server, and an access token will be returned to the caller. 176// 177// In some cases we need to display a sign-in dialog. Normally the 178// profile will be signed in already, but if it turns out we need a 179// new login token, there is a sign-in flow. If that flow completes 180// successfully, getAuthToken proceeds to the non-interactive flow. 181class IdentityGetAuthTokenFunction : public ChromeAsyncExtensionFunction, 182 public GaiaWebAuthFlow::Delegate, 183 public IdentityMintRequestQueue::Request, 184 public OAuth2MintTokenFlow::Delegate, 185 public IdentitySigninFlow::Delegate, 186 public OAuth2TokenService::Consumer, 187 public IdentityAPI::ShutdownObserver { 188 public: 189 DECLARE_EXTENSION_FUNCTION("identity.getAuthToken", 190 EXPERIMENTAL_IDENTITY_GETAUTHTOKEN); 191 192 IdentityGetAuthTokenFunction(); 193 194 protected: 195 virtual ~IdentityGetAuthTokenFunction(); 196 197 private: 198 FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest, 199 ComponentWithChromeClientId); 200 FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest, 201 ComponentWithNormalClientId); 202 FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest, InteractiveQueueShutdown); 203 FRIEND_TEST_ALL_PREFIXES(GetAuthTokenFunctionTest, NoninteractiveShutdown); 204 friend class MockGetAuthTokenFunction; 205 206 // ExtensionFunction: 207 virtual bool RunAsync() OVERRIDE; 208 209 // Helpers to report async function results to the caller. 210 void StartAsyncRun(); 211 void CompleteAsyncRun(bool success); 212 void CompleteFunctionWithResult(const std::string& access_token); 213 void CompleteFunctionWithError(const std::string& error); 214 215 // Initiate/complete the sub-flows. 216 void StartSigninFlow(); 217 void StartMintTokenFlow(IdentityMintRequestQueue::MintType type); 218 void CompleteMintTokenFlow(); 219 220 // IdentityMintRequestQueue::Request implementation: 221 virtual void StartMintToken(IdentityMintRequestQueue::MintType type) OVERRIDE; 222 223 // OAuth2MintTokenFlow::Delegate implementation: 224 virtual void OnMintTokenSuccess(const std::string& access_token, 225 int time_to_live) OVERRIDE; 226 virtual void OnMintTokenFailure( 227 const GoogleServiceAuthError& error) OVERRIDE; 228 virtual void OnIssueAdviceSuccess( 229 const IssueAdviceInfo& issue_advice) OVERRIDE; 230 231 // IdentitySigninFlow::Delegate implementation: 232 virtual void SigninSuccess() OVERRIDE; 233 virtual void SigninFailed() OVERRIDE; 234 235 // GaiaWebAuthFlow::Delegate implementation: 236 virtual void OnGaiaFlowFailure(GaiaWebAuthFlow::Failure failure, 237 GoogleServiceAuthError service_error, 238 const std::string& oauth_error) OVERRIDE; 239 virtual void OnGaiaFlowCompleted(const std::string& access_token, 240 const std::string& expiration) OVERRIDE; 241 242 // OAuth2TokenService::Consumer implementation: 243 virtual void OnGetTokenSuccess(const OAuth2TokenService::Request* request, 244 const std::string& access_token, 245 const base::Time& expiration_time) OVERRIDE; 246 virtual void OnGetTokenFailure(const OAuth2TokenService::Request* request, 247 const GoogleServiceAuthError& error) OVERRIDE; 248 249 // IdentityAPI::ShutdownObserver implementation: 250 virtual void OnShutdown() OVERRIDE; 251 252 // Starts a login access token request. 253 virtual void StartLoginAccessTokenRequest(); 254 255#if defined(OS_CHROMEOS) 256 // Starts a login access token request for device robot account. This method 257 // will be called only in enterprise kiosk mode in ChromeOS. 258 virtual void StartDeviceLoginAccessTokenRequest(); 259#endif 260 261 // Starts a mint token request to GAIA. 262 void StartGaiaRequest(const std::string& login_access_token); 263 264 // Methods for invoking UI. Overridable for testing. 265 virtual void ShowLoginPopup(); 266 virtual void ShowOAuthApprovalDialog(const IssueAdviceInfo& issue_advice); 267 // Caller owns the returned instance. 268 virtual OAuth2MintTokenFlow* CreateMintTokenFlow( 269 const std::string& login_access_token); 270 271 // Checks if there is a master login token to mint tokens for the extension. 272 virtual bool HasLoginToken() const; 273 274 // Maps OAuth2 protocol errors to an error message returned to the 275 // developer in chrome.runtime.lastError. 276 std::string MapOAuth2ErrorToDescription(const std::string& error); 277 278 std::string GetOAuth2ClientId() const; 279 280 bool should_prompt_for_scopes_; 281 IdentityMintRequestQueue::MintType mint_token_flow_type_; 282 scoped_ptr<OAuth2MintTokenFlow> mint_token_flow_; 283 OAuth2MintTokenFlow::Mode gaia_mint_token_mode_; 284 bool should_prompt_for_signin_; 285 286 scoped_ptr<ExtensionTokenKey> token_key_; 287 std::string oauth2_client_id_; 288 // When launched in interactive mode, and if there is no existing grant, 289 // a permissions prompt will be popped up to the user. 290 IssueAdviceInfo issue_advice_; 291 scoped_ptr<GaiaWebAuthFlow> gaia_web_auth_flow_; 292 scoped_ptr<IdentitySigninFlow> signin_flow_; 293 scoped_ptr<OAuth2TokenService::Request> login_token_request_; 294}; 295 296class IdentityRemoveCachedAuthTokenFunction 297 : public ChromeSyncExtensionFunction { 298 public: 299 DECLARE_EXTENSION_FUNCTION("identity.removeCachedAuthToken", 300 EXPERIMENTAL_IDENTITY_REMOVECACHEDAUTHTOKEN) 301 IdentityRemoveCachedAuthTokenFunction(); 302 303 protected: 304 virtual ~IdentityRemoveCachedAuthTokenFunction(); 305 306 // SyncExtensionFunction implementation: 307 virtual bool RunSync() OVERRIDE; 308}; 309 310class IdentityLaunchWebAuthFlowFunction : public ChromeAsyncExtensionFunction, 311 public WebAuthFlow::Delegate { 312 public: 313 DECLARE_EXTENSION_FUNCTION("identity.launchWebAuthFlow", 314 EXPERIMENTAL_IDENTITY_LAUNCHWEBAUTHFLOW); 315 316 IdentityLaunchWebAuthFlowFunction(); 317 318 // Tests may override extension_id. 319 void InitFinalRedirectURLPrefixForTest(const std::string& extension_id); 320 321 private: 322 virtual ~IdentityLaunchWebAuthFlowFunction(); 323 virtual bool RunAsync() OVERRIDE; 324 325 // WebAuthFlow::Delegate implementation. 326 virtual void OnAuthFlowFailure(WebAuthFlow::Failure failure) OVERRIDE; 327 virtual void OnAuthFlowURLChange(const GURL& redirect_url) OVERRIDE; 328 virtual void OnAuthFlowTitleChange(const std::string& title) OVERRIDE {} 329 330 // Helper to initialize final URL prefix. 331 void InitFinalRedirectURLPrefix(const std::string& extension_id); 332 333 scoped_ptr<WebAuthFlow> auth_flow_; 334 GURL final_url_prefix_; 335}; 336 337} // namespace extensions 338 339#endif // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_ 340