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