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