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