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 26 class GoogleServiceAuthError; 27 class MockGetAuthTokenFunction; 28 class Profile; 29 30 namespace extensions { 31 32 class GetAuthTokenFunctionTest; 33 class MockGetAuthTokenFunction; 34 35 namespace identity_constants { 36 extern const char kInvalidClientId[]; 37 extern const char kInvalidScopes[]; 38 extern const char kAuthFailure[]; 39 extern const char kNoGrant[]; 40 extern const char kUserRejected[]; 41 extern const char kUserNotSignedIn[]; 42 extern const char kInteractionRequired[]; 43 extern const char kInvalidRedirect[]; 44 extern const char kOffTheRecord[]; 45 extern 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. 65 class 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 166 class 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 179 class 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 206 class 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 236 class 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 void Initialize(); 254 255 // Request serialization queue for getAuthToken. 256 IdentityMintRequestQueue* mint_queue(); 257 258 // Token cache 259 void SetCachedToken(const std::string& extension_id, 260 const std::vector<std::string> scopes, 261 const IdentityTokenCacheValue& token_data); 262 void EraseCachedToken(const std::string& extension_id, 263 const std::string& token); 264 void EraseAllCachedTokens(); 265 const IdentityTokenCacheValue& GetCachedToken( 266 const std::string& extension_id, const std::vector<std::string> scopes); 267 268 const CachedTokens& GetAllCachedTokens(); 269 270 void ReportAuthError(const GoogleServiceAuthError& error); 271 272 // ProfileKeyedAPI implementation. 273 virtual void Shutdown() OVERRIDE; 274 static ProfileKeyedAPIFactory<IdentityAPI>* GetFactoryInstance(); 275 276 // AuthStatusProvider implementation. 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 bool initialized_; 294 IdentityMintRequestQueue mint_queue_; 295 CachedTokens token_cache_; 296 }; 297 298 template <> 299 void ProfileKeyedAPIFactory<IdentityAPI>::DeclareFactoryDependencies(); 300 301 } // namespace extensions 302 303 #endif // CHROME_BROWSER_EXTENSIONS_API_IDENTITY_IDENTITY_API_H_ 304