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