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