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