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